第一次码的完整的python代码

主要目的

熟悉一下python 类,tkinter的使用,pyinstaller实现的对py直接封装成exe 以及水掉python期末的300行大作业

模拟炮弹

这个简陋的程序时用来模拟炮弹的飞行,通过输入炮弹的角度以及速度以使炮弹命中靶子。

功能包括

  1. 自行选择游戏难度(影响靶子的大小)
  2. 可存储的游戏排名(只包括前10名)
  3. 部分可能的非法输入时提示错误

界面截图




链接

emm这里是封装好了的exe

代码

程序的各个部分的注解都标上去了
使用了大量的GUI界面(不然我咋弄个300行来 )以及类
其实代码的核心功能实现非常简单.
以下是核心代码的实现:即从控制台输入相关参数实现炮弹轨迹

from graphics import *
import time
import math
from random import randint
##l为标靶的长度,h为标靶的高度
l=10
h=4
class Projectile:
    def __init__(self, angle, vel, height):
        self.xpos = 0.0
        self.ypos = height
        theta = math.radians(angle)
        self.xvel = vel * math.cos(theta)##x方向初速度
        self.yvel = vel * math.sin(theta)##y方向初速度
    def getX(self):
        return self.xpos
    def getY(self):
        return self.ypos
    def update(self, time):
        self.xpos = self.xpos + time * self.xvel
        yvel1 = self.yvel - time * 9.8
        self.ypos = self.ypos + time * (self.yvel + yvel1)/2.0
        self.yvel = yvel1
    def highest(self):
        return self.ypos+0.5*9.8*(self.yvel/9.8)**2
    
def getInputs():
    a = float(input("输入你要发射炮弹的角度 (度数): "))
    v = float(input("发射炮弹的速度 (米/秒): "))
    h = float(input("发射台的高度 (米): "))
    return a,v,h

class ShotTracker:
    def __init__(self, win, angle, velocity, height):    
        self.proj = Projectile(angle, velocity, height)
        self.marker = Circle(Point(0,height), 2)
        self.marker.setFill("red")
        self.marker.setOutline("red")
        self.marker.draw(win)
    def update(self, dt):
        self.proj.update(dt)
        # move the circle to the new projectile location
        center = self.marker.getCenter()
        dx = self.proj.getX() - center.getX()
        dy = self.proj.getY() - center.getY()
        self.marker.move(dx,dy)
    def getX(self):
        return self.proj.getX()
    def getY(self):
        """ return the current y coordinate of the shot’s center """
        return self.proj.getY()
    def undraw(self):
        """ undraw the shot """
        self.marker.undraw()
def main():
    # 打印出窗口
    win = GraphWin("Projectile Animation", 960, 480, autoflush=False)
    win.setCoords(-10, -10, 312, 155)
    #打印一个随机位置的标靶
    tag_x=randint(10+l,315)
    Line(Point(tag_x-l/2,h), Point(tag_x+l/2,h)).draw(win)
    Line(Point(tag_x-l/2,0), Point(tag_x-l/2,h)).draw(win)
    Line(Point(tag_x+l/2,0), Point(tag_x+l/2,h)).draw(win)
    # 打印出坐标轴
    Line(Point(-10,0), Point(315,0)).draw(win)
    # 打印坐标轴上的距离
    for x in range(0, 315, 50):
        Text(Point(x,-5), str(x)).draw(win)
        Line(Point(x,0), Point(x,2)).draw(win)
    n=0
    flag=0#标记有无命中以跳出循环
    while 1:
        if flag==1:
            break
        if n>0:#为了能先把坐标轴打印出来
            angle, vel, height = getInputs()
        else:#先进行一次无效射击
            angle, vel, height=0,0,0
        shot = ShotTracker(win, angle, vel, height)
        t_s=0
        while 0 <= shot.getY() and -10 < shot.getX() <= 315:
            shot.update(0.005)
            if 0 <=shot.getY() <=h and tag_x-l/2 < shot.getX() <= tag_x+l/2:
                print("你击中了")
                flag=1;
                break;
            s_t=0.001-0.000001*t_s**1.2
            if s_t<0:
                s_t=0.0000001
            time.sleep(s_t)
            update()
            t_s+=1
        if flag==0 and n!=0:
            print("错失!")
        n+=1
    
main()

以下是带GUI界面的版本

#coding=gbk
import tkinter as tk
from tkinter.messagebox import *
from graphics import *
import time
import math
from random import randint
##l为标靶的长度,h为标靶的高度
angle,vel,height=0,0,0
player=''
try_t=0
his_n=[]
his_t=[]
le=10
he=4
class RegUi(tk.Frame):#输入昵称的部分
    def __init__(self):
        self.Reg=tk.Toplevel()
        self.Reg.title('昵称')
        tk.Frame.__init__(self,master=self.Reg)
        self.pack()
        sw = self.Reg.winfo_screenwidth()
        #得到屏幕宽度
        sh = self.Reg.winfo_screenheight()
        x=(sw-200)/2
        y=(sh-80)/2
        self.Reg.geometry("200x80+%d+%d" %(x,y))
        #这里是学习一下实现窗口居中
        self.createWidgets()   
    def createWidgets(self):
        self.PName=tk.Label(self,text='输入你的昵称')
        self.PName.pack(side='top')
        self.Name=tk.Entry(self)
        self.Name.pack()
        btnOk=tk.Button(self,text='开始游戏',command=self.GetName)
        btnOk.pack(side='bottom')
    def GetName(self):
        global player
        player=self.Name.get()
        if player=='':
            showwarning(title='错误!',message='昵称不能为空')
        else:
            self.Reg.destroy()
            Getinputs()
class Gamegui(tk.Frame):#这里是实现开始游戏的地方
#内容包括顶部菜单栏的难度选择部分,底部的开始,查看排名,退出游戏以及关于本人的个人信息
    def __init__(self,master=None):
        tk.Frame.__init__(self,master)
        self.pic=tk.PhotoImage(file = 'bg-start.gif')
        self.pack()
        self.Menubar=tk.Menu(self)
        self.createMenu()
        root['menu']=self.Menubar
        self.createWidgets()
    def createMenu(self):
        self.menuhard=tk.Menu(self.Menubar,tearoff=0)
        self.Menubar.add_cascade(label='难度',menu=self.menuhard)
        self.menuhard.add_command(label='简单',command=self.easy)
        self.menuhard.add_command(label='普通',command=self.normal)
        self.menuhard.add_command(label='困难',command=self.hard)
        self.menuhard.add_command(label='地狱',command=self.leg)
    def createWidgets(self):
        self.bgImage=tk.Label(self,width=300,height=300)
        self.bgImage['image']=self.pic
        self.bgImage.pack(expand='1')
        self.btnStart=tk.Button(self,text='开始游戏',font=("微软雅黑"), fg="red",command=self.start).pack(side='left')
        self.btnRank=tk.Button(self,text='查看排名',font=("微软雅黑"), fg="red",command=self.rank).pack(side='left')
        self.btnAbout=tk.Button(self,text='关于',font=("微软雅黑",6),command=self.about,pady=15).pack(side='right')
        self.btnQuit=tk.Button(self,text='退出游戏',font=("微软雅黑"), fg="red",command=self.quit).pack(side='right')
    def easy(self):
        global le
        global he
        le=10
        he=4
        showinfo(title='提示',message='当前难度是简单!不计入排行榜!')
    def normal(self):
        global le
        global he
        le=8
        he=3
        showinfo(title='提示',message='当前难度是普通!不计入排行榜!')
    def hard(self):
        global le
        global he
        le=6
        he=2
        showinfo(title='提示',message='当前难度是困难!计入排行榜!')
    def leg(self):
        global le
        global he
        le=2
        he=1
        showinfo(title='提示',message='当前难度是地狱!计入排行榜,并且射击次数减半!兄弟好勇气!')
    def start(self):
        global len
        if le > 6:
            showerror(title='提示',message='当前难度不是困难或者地狱,将不会记录排名中!')
        self.ent_name=tk.Frame()
        self.pack()
        RegUi()
    def rank(self):
        global his_n
        global his_t
        str1='排行榜如下:\n'
        for i in range(0,len(his_n)):
            str1+='第'
            str1+=str(i+1)
            str1+='名---'
            str1+='玩家:'
            str1+=his_n[i]
            str1+='     发射次数:'
            str1+=str(his_t[i])
            str1+='\n'
        showinfo(title='排名',message=str1)
    def quit(self):
        root.destroy()
    def about(self):#别骂了别骂了,垃圾学校,垃圾学校,跟各位大佬比不了
        str1=''
        str1+='注意:\n本程序由\n华东交通大学\n2019级软件工程9班\n乐嘉伟完成\n版权所有\nv1.0.0'
        showinfo(title='关于',message=str1)


class Projectile:#这里是对炮弹轨迹进行计算
    def __init__(self, angle, vel, height):
        self.xpos = 0.0
        self.ypos = height
        theta = math.radians(angle)
        self.xvel = vel * math.cos(theta)##x方向初速度
        self.yvel = vel * math.sin(theta)##y方向初速度
    def getX(self):
        return self.xpos
    def getY(self):
        return self.ypos
    def update(self, time):
        self.xpos = self.xpos + time * self.xvel
        yvel1 = self.yvel - time * 9.8
        self.ypos = self.ypos + time * (self.yvel + yvel1)/2.0
        self.yvel = yvel1
    def highest(self):
        return self.ypos+0.5*9.8*(self.yvel/9.8)**2
class Getinputs:
    def __init__(self):
        self.a=tk.StringVar()#这里是纯粹的学习。。。不晓得这里用这个有啥子用那
        self.v=tk.StringVar()
        global le
        global he
        self.l=le
        self.h=he
        self.n=0#这里本来也想输入的,然后感觉意义不大来着
        self.win = GraphWin("游戏界面", 960, 480, autoflush=False)
        self.win.setCoords(-10, -10, 312, 155)
        #打印一个随机位置的标靶
        self.tag_x=randint(10+self.l,315)
        Line(Point(self.tag_x-self.l/2,self.h), Point(self.tag_x+self.l/2,self.h)).draw(self.win)
        Line(Point(self.tag_x-self.l/2,0), Point(self.tag_x-self.l/2,self.h)).draw(self.win)
        Line(Point(self.tag_x+self.l/2,0), Point(self.tag_x+self.l/2,self.h)).draw(self.win)
        # 打印出坐标轴
        Line(Point(-10,0), Point(315,0)).draw(self.win)
         # 打印坐标轴上的距离
        for x in range(0, 315, 50):
            Text(Point(x,-5), str(x)).draw(self.win)
            Line(Point(x,0), Point(x,2)).draw(self.win)
        self.InPut=tk.Toplevel()
        self.InPut.title('发射参数')
        self.Label_v=tk.Label(self.InPut,text='炮弹发射速度')
        self.Label_v.grid(row=0,column=0)
        self.Scale_v=tk.Scale(self.InPut,from_=1,to=80,length=100,orient=tk.HORIZONTAL,resolution=1,showvalue=1,variable=self.v)
        self.Scale_v.grid(row=0,column=2)
        self.Label_a=tk.Label(self.InPut,text='炮弹发射角度')
        self.Label_a.grid(row=1,column=0)
        self.Scale_a=tk.Scale(self.InPut,from_=90,to=1,length=100,orient=tk.VERTICAL,resolution=1,showvalue=1,variable=self.a)
        self.Scale_a.grid(row=1,column=1)
        self.Pic=tk.PhotoImage(file = 'bg-fire.gif')
        self.bgImage=tk.Label(self.InPut,width=100,height=100)
        self.bgImage['image']=self.Pic
        self.bgImage.grid(row=1,column=2)
        self.BtnOk=tk.Button(self.InPut,text='发射!',command=self.playgame).grid(row=2,column=2)
        self.InPut.mainloop()
    def playgame(self):
        angle, vel, height=int(self.a.get()),int(self.v.get()),0
        flag=0#标记有无命中以跳出循环
        shot = ShotTracker(self.win, angle, vel, height)
        while 0 <= shot.getY() and -10 < shot.getX() <= 315:
            shot.update(0.005)
            if 0 <=shot.getY() <=self.h and self.tag_x-self.l/2 < shot.getX() <= self.tag_x+self.l/2:
                flag=1;
                break;
            time.sleep(0.001)
            update()
        self.n+=1
        if flag==0:
            if shot.getY()>0:
                showinfo(title='太可惜了',message='错失!'+'\n'+'你射出界了!\n'+'这是你第'+str(self.n)+'次尝试'+'\n'+'再接再厉,加油!')
            else:
                showinfo(title='太可惜了',message='错失!'+'\n'+'你射到'+str(int(shot.getX()))+'米了!\n'+'这是你第'+str(self.n)+'次尝试'+'\n'+'再接再厉,加油!')
        
        else:
            global player
            global try_t
            global le
            try_t=self.n
            self.InPut.destroy()
            showinfo(title='干得漂亮!',message='干得漂亮!'+player+'\n'+'你击中了靶子!'+'\n'+'你尝试了:'+str(self.n)+'次')
            if le<=6:
                Update_rec()
            else:
                showinfo(title='注意!',message='你的当前难度不是困难,不配进入排行榜!!加油吧骚年!')
            self.win.close()
            
        

class ShotTracker:
    def __init__(self, win, angle, velocity, height):    
        self.proj = Projectile(angle, velocity, height)
        self.marker = Circle(Point(0,height), 2)
        self.marker.setFill("red")
        self.marker.setOutline("red")
        self.marker.draw(win)
    def update(self, dt):
        self.proj.update(dt)
        # move the circle to the new projectile location
        center = self.marker.getCenter()
        dx = self.proj.getX() - center.getX()
        dy = self.proj.getY() - center.getY()
        self.marker.move(dx,dy)
    def getX(self):
        return self.proj.getX()
    def getY(self):
        """ return the current y coordinate of the shot’s center """
        return self.proj.getY()
    def undraw(self):
        """ undraw the shot """
        self.marker.undraw()
def Update_rec():
    global player
    global try_t
    global his_n
    global his_t
    global le
    temp=0
    if le ==2:
        showinfo(title='牛逼',message='我真的没想到还真有人能击中!!!')
        try_t/=2
        try_t=int(try_t)
        player+='------(地狱勇士)'
    for i in range(0,len(his_n)):
        if his_t[i]<try_t:
            temp+=1
        else:
            break
    his_n.insert(temp,player)
    his_t.insert(temp,try_t)
    ##保存进文件##
    fo = open("rank.txt", "r+")
    up_n=0
    if len(his_n)>=10:
        up_n=10
    else:
        up_n=len(his_n)
    for i in range(0,len(his_n)):       
        fo.write( his_n[i]+' '+str(his_t[i]))
        if i != len(his_n)-1:
            fo.write('\n')
    fo.close()
    ##############
##从文件输入历史记录###
fo = open("rank.txt", "r")
ti=0
for line in fo.readlines():                          #依次读取每行  
    line = line.strip()#去掉每行头尾空白
    name=''
    times=''
    ptr=0
    while 1:
        if line[ptr]==' ':
            ptr+=1
            break;
        name+=line[ptr]
        ptr+=1
    for i in range(ptr,len(line)):
        times+=line[ptr]
        ptr+=1
    his_n.append(name)
    his_t.append(int(times))
    ti+=1
fo.close()
#####################
root = tk.Toplevel()  
root.title('炮弹发射')
game=Gamegui(master=root)
game.mainloop()



更多推荐

Python 模拟炮弹GUI 界面实现