1. 程式人生 > 其它 >20212306實驗四 Python綜合實踐

20212306實驗四 Python綜合實踐

20212306實驗四 Python綜合實踐

目錄
課程:《Python程式設計》
班級: 2123
姓名: 張陽
學號:20212306
實驗教師:王志強
實驗日期:2022年5月20日
必修/選修: 公選課

一學期的python課程落下帷幕,在王志強老師的指導下,我也算是對python有了一定的瞭解。但是相較於有一定程式設計基礎的同學來說,我的水平也就只是剛入門的級別。這次綜合實踐的選題我選擇了編寫貪吃蛇小遊戲,雖然這個遊戲可能對其他的同學很簡單,但是對於我來說,還是具有一定挑戰性,因此我花費了一些時間和精力,盡我所能完成了我所能達到的層次。在此分享一下我的思考過程和總結反思。

編寫程式碼時的心路歷程

我們首先可以將螢幕分成若干個等面積小塊,以便後面更容易理解分析。

主要需要解決的兩個點

1.如何讓蛇“走”起來————跟隨
後面一個格子跑到前面一個格子,一個一個代替。後一個格子跟著前一個格子走,頭跟著控制器的方向走。
2.怎麼將食物吃到肚子裡————吃的過程
如果蛇頭和食物重合,就需要將該格子與蛇頭合併,並且在尾部增加一格。

相關思路的技術解決

pygame
專門做遊戲的一個庫,幫助繪製圖形,捕捉事件,幫助聯網,幫助連線遊戲控制器。
Pygame三大物件
·Pygame.display 顯示
·Pygame.time 掌管時間
·Pygame.event事件相關(比如說使用者點了一下,使用者把遊戲關了)

整體思路框架

構建框架→繪製場景→繪製蛇頭、食物→移動蛇頭→繪製蛇身→吃到食物

構建框架

對框架本身進行初始化,然後決定畫面大小。

pygame.init()

size元組,寬高,顯示出來視窗

W = 800
H = 600
size = (W, H) 

顯示和繪圖相關

pygame.display

此時執行有兩個問題,視窗沒有標題,且只存在一瞬間。
那麼該怎麼解決呢?

設定標題我們可以採用

set_caption
pygame.display.set_caption('貪吃蛇')

為了不讓他只存在一瞬間,我們需要實現遊戲的迴圈。
While一直迴圈下去,但是不能一直迴圈下去,使用者選擇退出時應該不綁架人家,允許人家退出遊戲。準備一個變數quit。

進行時間控制

clock=pygame

設定一個幀頻,幀頻的作用是什麼呢,大概是可以控制你的蛇跑的快慢吧。

clock.tick(x)
clock.tick(20)

處理事件
1.遊戲退出問題
處理事件佇列

pygame.event.get() p

在event內部處理各種事情
Quit=False,就可以做遊戲的收尾工作了
但是還是會退出,那麼現在就需要渲染。
pygame.display渲染 flip讓出控制權,把控制權交給系統進行渲染,各種各樣的工作
pygame.display.flip()

畫圖

pygame.draw.rect

需要考慮畫的小方塊和方塊的顏色。

pygame.draw.rect(
        window, color,
        (left, top, cell_width, cell_height)
    )

繪製場景

場景到底長什麼樣子?
每個格子可以是蛇頭,蛇身,也可以是蛇的食物。我們看到的是移動的蛇頭,和食物,但在計算機裡呈現的就是二維陣列。

!!!搞清楚:格子體現出來,怎麼畫出來格子

將格子體現出來
row=100有多少行格子有多少列格子
因為有了螢幕的長和寬,所以通過除法,潛在的得到了每個格子有多大
畫格子
Point物件,每個格子都能用座標的形式表現出來,更加直觀清晰,直接定義每個東西所在位置

class Point:
    row = 0
    col = 0

    def __init__(self, row, col):
        self.row = row
        self.col = col

    def copy(self):
        return Point(row=self.row, col=self.col)

繪製蛇頭

開始定義蛇頭,初始位置區在中間(同時需要考慮到如果格子橫向數目為奇數的情況)
head = Point(row=int(ROW / 2), col=int(COL / 2))
定義食物的位置

def gen_food():
    while 1:
        pos = Point(row=random.randint(0, ROW - 1), col=random.randint(0, COL - 1))

雖然定義了,但是我們需要給他們畫出來。
根據據上方的距離和據一側的距離實現定位。
Left=所在的列每個格子有多寬 top是所在的行每個格子的高
rect函式
draw開始畫畫,顏色、位置、長寬高
可以通過上述內容進行蛇頭和食物的繪製。

移動蛇頭

如果朝左移動,row不動,col動。其他方向同理。

  if direct == 'left':
        head.col -= 1
    elif direct == 'right':
        head.col += 1
    elif direct == 'up':
        head.row -= 1
    elif direct == 'down':
        head.row += 1

此時蛇頭已經可以開始移動,但是會發現蛇頭根本不受我的鍵盤控制,那麼怎麼通過上下左右鍵來控制蛇的移動方向呢?
很容易想到,通過“事件”event來解決。
pygame.KEYDOWM與鍵盤進行“溝通”.將各個鍵分別定義成上下左右,實現我用鍵盤來控制蛇的方向,不讓他失控。但是此時呢,蛇頭會從食物裡盲目的穿過去,先別擔心,一步一步來,我們現在已經實現了蛇頭的移動。

繪製蛇身

現在我們來思考一下,如何繪製蛇的身子?
我們有各種各樣的方法來繪製,比如說可以採取表格的方式一個一個表示,但很顯然,這不是最簡單的方式。
我們可以把蛇的身子存成一個列表,如何去用列表實現蛇身呢?

for event in pygame.event.get():
        if event.type == pygame.QUIT:
            quit = False
        elif event.type == pygame.KEYDOWN:
            if event.key == 273 or event.key == 119:
                if direct == 'left' or direct == 'right':
                    direct = 'up'
            elif event.key == 274 or event.key == 115:
                if direct == 'left' or direct == 'right':
                    direct = 'down'
            elif event.key == 276 or event.key == 97:
                if direct == 'up' or direct == 'down':
                    direct = 'left'
            elif event.key == 275 or event.key == 100:
                if direct == 'up' or direct == 'down':
                    direct = 'right'

在移動的過程當中,只需要做一件事,把原來的頭插到前面,把原來的尾巴給刪掉。
先處理身子,因為原來的頭的位置是需要的。
1.把原來的頭插入到snakes的頭上
snakes.insert(0, head.copy())
2.把snakes的最後一個刪掉
snakes.pop()
3.記得繪製蛇的身子,不然依舊只有蛇頭

食物隨機出現,被吃

隨機很容易

random

def gen_food():
    while 1:
        pos = Point(row=random.randint(0, ROW - 1), col=random.randint(0, COL - 1))

        #
        is_coll = False

那麼怎麼吃掉東西呢?(也就是,食物在接觸蛇頭後消失,而不是蛇穿過食物)
很簡單,只要蛇頭和食物的行列都一樣,那麼就吃掉了。等下,以為這就結束了?並不是,吃掉食物蛇當然要長大。再寫好幾行來實現增長一節蛇的長度嗎?不用,只需要不刪除就行。
eat = (head.row == food.row and head.col == food.col)

if not eat:
      snakes.pop()

但是實踐發現,蛇是長長了,但是食物並沒有消失
於是此時就要讓食物在新的位置出現。

    if eat:
        food = gen_food()

此時,還有遊戲已經大致完成,但是還是有一些小bug

一些小bug——遊戲的簡單完善

比如說,食物生成完全隨機,它有沒有可能生成在蛇的身子上。再者說,如果蛇撞到了牆是不是就需要讓遊戲結束?這都是初步完善需要考慮的問題。
1.食物生成
用函式表示,隨機生成幾個座標然後檢測一下是否和蛇碰上了,如果碰上了就需要重新生成。
如果和腦袋碰上,直接檢測。
如果和身子碰上,記得要寫迴圈。
生成食物,統一用函式來生成,避免潛在碰撞問題

def gen_food():
    while 1:
        pos = Point(row=random.randint(0, ROW - 1), col=random.randint(0, COL - 1))

        #
        is_coll = False

        # 是否跟蛇碰上了
        if head.row == pos.row and head.col == pos.col:
            is_coll = True

        # 蛇身子
        for snake in snakes:
            if snake.row == pos.row and snake.col == pos.col:
                is_coll = True
                break

        if not is_coll:
            break

2.關於撞牆和撞到自己
撞牆:如果他的列已經小於零,或者列小於零,或者他的列大於等於總列數,或者行大於等於總行數,說明他要掛了。
撞自己:如果列和行等於蛇的列和行。

dead = False
     # 1.撞牆
     if head.col < 0 or head.row < 0 or head.col >= COL or head.row >= ROW:
         dead = True

     # 2.撞自己
     for snake in snakes:
         if head.col == snake.col and head.row == snake.row:
             dead = True
             break

3.如果死掉了
就顯示遊戲結束,並且自動退出程式

if dead:
     print('死了')
     quit = False

綜合實踐總結

綜合實踐到此就已經結束了,這次程式碼編寫的過程中讓我不僅對整個學期的學習內容有了很好的複習、總結和應用,還讓我自主學習到了更多的python的技能 ,雖然這個貪吃蛇小遊戲現在仍有很多的不足有待完善,我相信通過日後的學習精進,掌握更多知識後,我將會這個小遊戲進一步完善。

在華為雲伺服器上執行

原始碼

class Point:
  row=0
  col=0
  def __init__(self, row, col):
    self.row=row
    self.col=col
 
  def copy(self):
    return Point(row=self.row, col=self.col)
 
 
#初始框架
import pygame
import random
 
#初始化
pygame.init()
W=800
H=600
 
ROW=30
COL=40
 
size=(W,H)
window=pygame.display.set_mode(size)
pygame.display.set_caption('貪吃蛇')
 
bg_color=(255,255,255)
snake_color=(200,200,200)
 
head=Point(row=int(ROW/2), col=int(COL/2))
head_color=(0,128,128)
 
snakes=[
  Point(row=head.row, col=head.col+1),
  Point(row=head.row, col=head.col+2),
  Point(row=head.row, col=head.col+3)
]
 
#生成食物
def gen_food():
  while 1:
    pos=Point(row=random.randint(0,ROW-1), col=random.randint(0,COL-1))
 
    #
    is_coll=False
 
    #是否跟蛇碰上了
    if head.row==pos.row and head.col==pos.col:
      is_coll=True
 
    #蛇身子
    for snake in snakes:
      if snake.row==pos.row and snake.col==pos.col:
        is_coll=True
        break
 
    if not is_coll:
      break
 
  return pos
 
 
#定義座標
 
 
food=gen_food()
food_color=(255,255,0)
 
 
 
direct='left'       #left,right,up,down
 
#
def rect(point, color):
  cell_width=W/COL
  cell_height=H/ROW
 
  left=point.col*cell_width
  top=point.row*cell_height
 
  pygame.draw.rect(
    window, color,
    (left, top, cell_width, cell_height)
  )
  pass
 
#遊戲迴圈
quit=True
clock=pygame.time.Clock()
while quit:
  #處理事件
  for event in pygame.event.get():
    if event.type==pygame.QUIT:
      quit=False
    elif event.type==pygame.KEYDOWN:
      if event.key==273 or event.key==119:
        if direct=='left' or direct=='right':
          direct='up'
      elif event.key==274 or event.key==115:
        if direct == 'left' or direct == 'right':
          direct='down'
      elif event.key==276 or event.key==97:
        if direct == 'up' or direct == 'down':
          direct='left'
      elif event.key==275 or event.key==100:
        if direct == 'up' or direct == 'down':
          direct='right'
 
  #吃東西
  eat=(head.row==food.row and head.col==food.col)
 
  #重新產生食物
  if eat:
    food = gen_food()
 
  #處理身子
  #1.把原來的頭,插入到snakes的頭上
  snakes.insert(0, head.copy())
  #2.把snakes的最後一個刪掉
  if not eat:
    snakes.pop()
 
  #移動
  if direct=='left':
    head.col-=1
  elif direct=='right':
    head.col+=1
  elif direct=='up':
    head.row-=1
  elif direct=='down':
    head.row+=1
 
  #檢測
  dead=False
  #1.撞牆
  if head.col<0 or head.row<0 or head.col>=COL or head.row>=ROW:
    dead=True
 
  #2.撞自己
  for snake in snakes:
    if head.col==snake.col and head.row==snake.row:
      dead=True
      break
 
  if dead:
    print('死了')
    quit=False
 
  #渲染——畫出來
  #背景
  pygame.draw.rect(window, bg_color, (0,0,W,H))
 
  #蛇頭
  for snake in snakes:
    rect(snake, snake_color)
  rect(head, head_color)
  rect(food, food_color)
 
  #
  pygame.display.flip()
 
  #設定幀頻
  clock.tick(20)

實驗中遇到的困難

問題1.寫程式碼的時候會遇到很多困難的地方
解決:去CSDN上參考別人的程式碼,對比發現自己的程式碼問題在哪裡以及是否可以寫的更簡單。去b站參考一些視訊。
問題2:無法在華為雲伺服器上執行python程式
解決:這一部分真的花了好長好長的時間,從如何把python2的預設版本到改換成python3 ,如何下pygame應用,因為寫的是小遊戲需要視覺化,又花了很久的時間去研究如何用xming在putty中將遊戲介面調出。其中遇到了很多很多困難,一度有過想放棄的念頭,但是在課代表和學長學姐的幫助下,以及自己不斷地搜搜搜,問問問,終於實現了在華為雲伺服器上的成功執行!在此還是十分感謝課代表不離不棄的指導!!!

全課進行總結,課程感想體會、意見和建議

⭐經過這一學期學習,我瞭解了Python的語言基礎、流程控制語句、有關字串的操作、檔案操作、正則表示式、網路爬蟲、Socket程式設計、Python操作資料庫等等。在老師的講解與指導下,我初步入門了python,並激發起了學習python的熱情 。雖然經歷了一個學期的python課程學習,但受限於個人水平,我仍有許許多多的知識需要進一步瞭解,並反覆練習加以鞏固。同時,課程給我帶來的還有自學的能力,老師在課堂上雖然講了很多內容,但是有更多的內容是需要我們課後進一步學習,深入研究的。俗話說“師傅領進門,修行靠個人”,老師為我們勾畫出了python的具體框架,更多的需要靠我們自己摸索,通過不斷地鞏固和深入學習,把基礎築的更牢,把大廈建的更高。python是一門使用廣泛的高效率的程式語言,學好這門語言更有利於我們以後程式碼編寫、大創研究等專案,但是光靠這一學期的課程明顯是不夠的,在以後的日子裡,我也會繼續保持學習熱情,堅持python的學習。
⭐另外,還特別喜歡王志強老師的講課方式,循循漸進,和藹可親。在講知識點的同時進行實踐操作,這一點會幫助我們更直觀更高效的學習。同時,王老師在講課的時候也會具體指出如果怎麼怎麼寫,程式碼就會出現什麼樣的錯誤,這一點讓我們對錯誤的寫法有了更深刻的認識,大大減少了以後犯錯的情況。
⭐十分十分感謝王志強老師這一個學期給我們帶來的課程講解,希望還有機會能在課堂上聆聽您的教誨!
⭐我也會在以後的日子裡,以不息為體,以日新為道,對知識始終保有最積極的態度和最大的熱情。