金沙国际官网_金沙国际平台登录

因为这个金沙国际官网_金沙国际平台登录网站与很多的大型澳门赌场都有合作,金沙国际官网_金沙国际平台登录尽职尽责,高效执行,保持好奇心,不断学习,追求卓越,点击进入金沙国际官网_金沙国际平台登录马上体验吧,所以现在也正式地开始了营业。

您的位置:金沙国际官网 > 编程 > pygame写贪吃蛇,的通讯方式总结

pygame写贪吃蛇,的通讯方式总结

发布时间:2019-11-03 10:36编辑:编程浏览(193)

    两种开发方式

    python小白尝试写游戏..

    本来觉得没什么可写的,因为网上这玩意一搜一大把,不过爬虫毕竟是python的一个大亮点,不说说感觉对不起这玩意
    基础点来说,python2写爬虫重点需要两个模块,urllib和urllib2,其实还有re
    先介绍下模块的一些常用功能
    urllib.urlopen('') #打开一个网址,只是打开,和open差不多
    urllib2.Request(url) #金沙国际官网,解析网址,这个可以省略,具体不是很懂,一些功能,比如加head头什么的也需要使用这个
    urllib.urlretrieve(url,filename) #下载用,把url提供的东西down下来,并用filename保存
    举个蜂鸟爬图片的例子,下面上伪代码:

    1.使用 vs 自带的可视化工具,不推荐。

    在 vs 的项目中添加 ‘数据集’,然后通过可视化的工具添加数据库为数据源,默认可添加 SQL Server 和 Oracle 等,添加 Mysql 前需要额外安装组件。

    优点,自带 sql 语句中特殊字符的转义,不会出现 sql 注入的问题,配合数据绑定可以在项目前期快速推进项目进度。

    缺点:可视化工具的使用并不流行,不利于开发团队的招募和项目后期的修改维护。许多常用的功能很难使用,如:存储过程,事务,连接池控制等。

    学了点pygame不知道那什么练手好,先拿贪吃蛇开刀吧.

    1、url解析
    2、打开url
    3、读取url,就是read()
    4、使用re.findall找到所有和图片有关系的地址,这里只jpg
    5、循环下载
    

    2.引用 mysql.data.dll ,在此基础上进行开发,推荐。

    完全由代码完成通讯过程。

    优点:可以方便的使用各种功能,

    缺点:在使用的过程中要注意许多坑,如:异常的捕获,sql 注入 , 非托管资源的释放等。


     


     

    一个游戏可以粗略的分为两个部分:

    金沙国际官网 1

    完整的通讯过程

    • 数据(变量)
    • 处理数据(函数,方法)

    看图上,图片链接格式是src="
    分析之后后面的事就好办了,下面上代码

    1.建立连接,连接分 “长连接” 和 “短连接” 

    长连接在高频次的通讯时快速高效,但是占用资源,在并发访问下容易耗尽网络资源,对于带宽较低的局域网来说,如果大量使用长连接,会占用网速,影响使用体验。

    短连接在使用时 open, 使用完成后 close,此时连接资源会进入连接池,等待下次连接时使用。虽然资源未被释放掉,但连接池的开销不大,是完全可以接受的。短连接一样需要考虑并发问题。

    短连接在使用完成后可以直接 dispose,或者使用 using(){} 来限定连接的作用域,使用完成后自动释放掉,不进入连接池,这种方式资源占用最少,但在需要反复建立连接的情况下连接效率较低。

    在实际开发的时候最好使用短连接,并在使用结束后关闭并放入连接池。

    string connStr = "server=127.0.0.1; port=3306; user id=user1; Password=pass1; database=data1; pooling = true";
    MySqlConnection conn = new MySqlConnection(connStr);
    conn.Open(); 
    conn.Close();
    

    设计变量

    import urllib
    import urllib2
    import re
    
    #处理地址,并获取页面全部的图片地址
    def get_image_url(url):
      #url_format = urllib2.Request(url) #1
      url_open = urllib.urlopen(url) #2
      url_read = url_open.read() #3
      re_value = re.compile('(?<=src=").*?.jpg')
      image_url_list = re.findall(re_value,url_read) #4
      return image_url_list
    
    #这个函数专门用来下载,前面两行是将图片连接中/前面的内容全部删除,留下后面的文件名用来保存文件的,try不说了,不清楚请翻回去看容错
    def down_image(image_url):
      rev = '^.*/'
      file_name = re.sub(rev,'',image_url)
      try:
        urllib.urlretrieve(image_url,file_name)
      except:
        print 'download %s fail' %image_url
      else:
        print 'download %s successed' %image_url
    
    if __name__ == '__main__':
      url = 'http://bbs.fengniao.com/forum/10384633.html'
      image_url_list = get_image_url(url)
      for image_url in image_url_list:
        down_image(image_url) #5
    

    2.使用连接创建 sql 命令并执行

    首先预想下,画面的那些部分需要存储在变量里

    困死,睡觉去。。。。。有时间再说说翻页什么的,就能爬网站了

    1.纯 sql 语句,执行后有三种返回方式:

    cmd.ExecuteScalar();  // 查询结果仅一行一列,直接接收

    string connStr = "server=127.0.0.1; port=3306; user id=user1; Password=pass1; database=data1; pooling = true";
    MySqlConnection conn = new MySqlConnection(connStr);
    conn.Open();
    MySqlCommand cmd = conn.CreateCommand();
    string name = "Tom";
    cmd.CommandText = string.Format("select  count(*) from student where Name = '{0}';", name);
    object obj = cmd.ExecuteScalar(); //可能未null
    int count = 0;
    if (!obj.Equals(DBNull.Value))
    {
      count = Convert.ToInt32(obj);
    }  
    conn.Close();  
    

     

     

    MySqlDataReader reader = cmd.ExecuteReader();  // 通过 reader 获得大量数据

    string connStr = "server=127.0.0.1; port=3306; user id=user1; Password=pass1; database=data1; pooling = true";
    MySqlConnection conn = new MySqlConnection(connStr);
    conn.Open();
    MySqlCommand cmd = conn.CreateCommand();
    cmd.CommandText = string.Format("select  Name from student;");
    MySqlDataReader reader = cmd.ExecuteReader();
    List<string> list = new List<string>();
    while (reader.Read())
    {
        list.Add(reader.GetString("Name"));
    }
    reader.Close();
    conn.Close();
    

     

    cmd.ExecuteNonQuery();  // 获得增删改语句执行后影响的行数

    string connStr = "server=127.0.0.1; port=3306; user id=user1; Password=pass1; database=data1; pooling = true";
    MySqlConnection conn = new MySqlConnection(connStr);
    conn.Open();
    MySqlCommand cmd = conn.CreateCommand();
    string name = "Tom";
    cmd.CommandText = string.Format("update student SET Name='Tommy' where Name = '{0}';", name);
    int count = cmd.ExecuteNonQuery();
    conn.Close();
    

     

    普通 sql 语句的缺点:如果上面例子中的 name 参数中带有单引号,整个 sql 语句将执行错误,因为未对特殊字符进行转义。主要特殊字符有单引号,反斜杠,# 等,而这些特殊字符在不同的使用情况下有时需要转义,有时不需要转义。Mysql 提供了类似 QUOTE(str) 这样的字符串处理函数,但不能完全满足要求。

    这就是 sql 注入,sql 注入的概念网上资料较多,在此不再赘述,而常用的解决方案是采用参数化的 sql 语句。

    金沙国际官网 2

     

    2.sql 语句和 sql 参数

    带有参数的 sql 语句和 sql 参数会分开传入数据库服务器中,服务器先将 sql 语句进行编译,然后将 sql 参数导入编译后的 sql 语句中(在此过程中自动对特殊字符进行转义),从而从根源上防止了 sql 注入的发生。

    string connStr = "server=127.0.0.1; port=3306; user id=user1; Password=pass1; database=data1; pooling = true";
    MySqlConnection conn = new MySqlConnection(connStr);
    conn.Open();
    MySqlCommand cmd = conn.CreateCommand();
    cmd.CommandText = "select  count(*) from student where Name = @Name;";
    MySqlParameter[] sps = new MySqlParameter[1];
    sps[0] = new MySqlParameter("@Name", "Tom");
    cmd.Parameters.AddRange(sps);
    object obj = cmd.ExecuteScalar(); //可能未null
    int count = 0;
    if (!obj.Equals(DBNull.Value))
    {
        count = Convert.ToInt32(obj);
    }   
    conn.Close();  
    

    整个画面上只会有矩形,而且这些矩形整整齐齐,大小相等,原本一个矩形需要四个变量表示位置,这里,只需要两个变量(行数,列数)就能表示方块的位置

    3.事务

    多条 sql 语句的组合会出现某一条 sql 语句执行出错,而其他 sql 语句顺利执行的情况,这可能与预期不符合。此时需要使用事务。

    事务在执行出错时可以回滚。

    事务往往带有多条 sql 语句,在使用参数化的 sql 语句时要注意参数名称不能相同。

    conn.Open();
    MySqlCommand cmd = conn.CreateCommand();
    MySqlTransaction myTrans = conn.BeginTransaction();
    cmd.Connection = conn;
    cmd.Transaction = myTrans;
    cmd.CommandText = "";
    cmd.ExecuteNonQuery();
    myTrans.Commit();
    conn.Close();
    

     

     

    蛇头,食物可以用二元元组表示,蛇身的数量不确定,只能用包含数个元组的列表表示

    4.存储过程

    不论是 sql 语句还是事务,在传输指令的时候都需要耗费大量的时间,数据库编译这些指令也需要耗费大量时间,这不利于高访问量的数据库的运行。

    存储过程是将 sql 指令写在数据库中,此时数据库直接完成编译,与数据库通讯是只需要传递参数即可。节省了传输时间和编译时间。

    conn.Open();
    MySqlCommand cmd = conn.CreateCommand();
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.CommandText = "SpFillStudent";
    
    MySqlParameter paraMoney;
    paraMoney = cmd.Parameters.Add("@inMoney", MySqlDbType.Decimal);
    paraMoney.Direction = ParameterDirection.Input;
    paraMoney.Value = 50;
    
    MySqlParameter paraTradeType;
    paraTradeType = cmd.Parameters.Add("@inTradeType", MySqlDbType.String);
    paraTradeType.Direction = ParameterDirection.Input;
    paraTradeType.Value = "会员卡充值";
    
    MySqlParameter paraPayDetailStr;
    paraPayDetailStr = cmd.Parameters.Add("@inPayDetailStr", MySqlDbType.String);
    paraPayDetailStr.Direction = ParameterDirection.Input;
    paraPayDetailStr.Value = "";
    
    MySqlParameter paraOutResult;
    paraOutResult = cmd.Parameters.Add("@outResult", MySqlDbType.String);
    paraOutResult.Direction = ParameterDirection.Output;
    
    cmd.ExecuteNonQuery();
    string result = (string)paraOutResult.Value;
    conn.Close();
    

     

    另外设定窗口大小800x600,每个方块都是50x50

    import pygame
    import sys
    
    pygame.init()
    screen = pygame.display.set_mode((800, 600))
    pygame.display.set_caption("贪吃蛇")
    
    food = (4, 5)
    body = [(1, 1),(1,2)]
    head = (1, 3)
    
    BLOCK = 0, 0, 0
    GREEN = 0, 255, 0
    RED = 255, 0, 0
    BLUE = 0, 0, 255
    WHITE = 255, 255, 255
    
    while 1:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
    

    变量设定好了,游戏已经完成了一半( ̄▽ ̄)~*

    下一步

    变量到画面

    pygame.draw.rect()是根据矩形四元数组绘制图像的,那就写个函数"对接"下我的二元坐标

    这里就成数学的问题了...

    def new_draw_rect(zb, color,screen):
        pygame.draw.rect(screen,color,((zb[1]-1)*50+1,(zb[0]-1)*50+1,48,48))
    

    鉴于50x50时相邻方块们会"粘"在一起,方块向里收一下成48x48        ↑

    绘制图形,

    ...
    while 1:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
    
        screen.fill(WHITE)
        new_draw_rect(food, RED, screen)
        for i in body:
            new_draw_rect(i, BLUE, screen)
        new_draw_rect(head, GREEN, screen)
    
        pygame.display.update()
    

     由静到动

     两个问题:

    1.什么时候动

    2.怎么动

    问题1,什么时候动,这里有两个思路,

    • 间隔固定时间(1秒),动一次
    • 按一次键动一次,无操作一定时间(1秒)后,重复最后一次操作

    看起来第一种方案 简单 不错

    首先,先用pygame的clock类限制帧率(100帧),以方便计时

    再者,加入新变量times,times每次加1,超过一百就"动一动"

    加入新变量direction,表示蛇头朝向,衔接键盘操作和"怎么动"

     PS:程序结束之前,很难知道要用多少变量

    import pygame
    import sys
    
    pygame.init()
    screen = pygame.display.set_mode((800, 600))
    pygame.display.set_caption("贪吃蛇")
    
    fclock = pygame.time.Clock()
    
    
    food = (4, 5)
    body = [(1, 1)]
    head = (1, 2)
    times = 0
    direction = 'right'
    
    BLOCK = 0, 0, 0
    GREEN = 0, 255, 0
    RED = 255, 0, 0
    BLUE = 0, 0, 255
    WHITE = 255, 255, 255
    
    def new_draw_rect(zb, color,screen):
        pygame.draw.rect(screen,color,((zb[1]-1)*50+1,(zb[0]-1)*50+1,48,48))
        pass
    
    
    while 1:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    direction = "up"
                elif event.key == pygame.K_LEFT:
                    direction = "left"
                elif event.key == pygame.K_DOWN:
                    direction = "down"
                elif event.key == pygame.K_RIGHT:
                    direction = "right"
        if times >= 100:
            pass#动一动
            times = 0
        else:
            times += 1
    
        screen.fill(WHITE)
        new_draw_rect(food, RED, screen)
        for i in body:
            new_draw_rect(i, BLUE, screen)
        new_draw_rect(head, GREEN, screen)
    
        fclock.tick(100)
        pygame.display.update()
    

     

     蛇头的运动规律 : 向临近的格子移动,上下左右具体那个格子由键盘确定

    那就写个新函数去生成蛇头的新位置

    def get_front(head,direction):
        x, y = head
        if direction == "up":
            return x-1, y
        elif direction == "left":
            return x, y-1
        elif direction == "down":
            return x+1, y
        elif direction == "right":
            return x, y+1
    

    然后

    head = get_front(head,direction)

    但是蛇蛇一头扎墙里怎么办.......

    你的好友【front : 临时记下蛇头前方的位置】已上线

    你的好友【alive : 记录存活信息】已上线

    PS:front可以不是全局变量

    def ask_alive(front,body):
        x, y = front
        if x < 0 or x > 12 or y < 0 or y >16 :
            return False
        if front in body:
            return False
        return True
    

    然后这样用

    front = get_front(head,direction)
    alive = ask_alive(front,body)
    if alive:
      head = front

    人话 :先看看蛇头前面是否有危险,有危险就死了 , 不动啦

    另外alive得加到前面的if里面当限制条件,死了就不能乱动啦~

     

    蛇身动的规律 : 近头端跟头走,尾端也跟着走--向程序靠拢-->>用过的head加入body,同时删去body最老的成员

    这里可以看出body必须有序,可变.python里面就用列表了

    如果使用list的append方法,head加在body的末尾,那么body[0]就会是"最老的成员"就得使用pop(0)删去

    PS. body.append(head)得写在head=front前面,在head更新前加进body

        if times >= 100 and alive:
            front = get_front(head,direction)
            alive = ask_alive(front,body)
            if alive:
                body.append(head)
                head = front
                body.pop(0)
            times = 0
        else:
            times += 1
    

     食物的运动规律:被吃掉后,随机位置再出现 --向程序靠拢-->> 当head== food为真时 food随机选择一个蛇之外的地方出现

    def new_food(head,body):
        while 1:
            x = random.randint(1, 12)
            y = random.randint(1, 16)
            if (x, y) != head and (x, y) not in body:
                return x, y
    

     

    这里存在一个隐式BUG,要是蛇充满了每一个角落,那这就是死循环 ...........然后整个程序卡在这里....

    版本1 : 我选择没看见,不会有什么人能吃到"全屏"的(´⊙ω⊙`)    --来自开发者的懒惰

    版本2 【我的选择】: 修了这个BUG

    def new_food(head,body):
        i = 0
        while i < 100:
            x = random.randint(1, 12)
            y = random.randint(1, 16)
            if (x, y) != head and (x, y) not in body:
                return (x, y), True
            i += 1
        else:
            return (0, 0), False
    
    food, alive = new_food()
    

     

     100次机会 否则就死( ̄へ ̄)     --来自开发者的恶意

    本文由金沙国际官网发布于编程,转载请注明出处:pygame写贪吃蛇,的通讯方式总结

    关键词:

上一篇:没有了

下一篇:没有了