1 Star 0 Fork 2

greedy-snake-projectsets / TrainSnake

forked from Trust04zh / TrainSnake 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
snake.py 22.92 KB
一键复制 编辑 原始数据 按行查看 历史
Trust04zh 提交于 2020-08-05 10:36 . 一些小调整
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
# -*- coding: utf-8 -*-
#Build with Python 2.7.15, pygame 1.9.6.
#运行本脚本需要系统支持黑体字体,或者你可以修改snake_init.py中的TEXT_FONT全局变量来切换字体
#棋盘界面的贴图分为三层,第一层是空地贴图,每个格子都有;第二层是轨道(分充电已/未完成);第三层是列车,乘客。
#格子编号对应关系:1空地,2横向轨道,3纵向轨道,4二维轨道
#方向:UDLR
import sys
import os
from time import sleep
from timeit import default_timer
from datetime import datetime
from random import randint
import pygame
from pygame.locals import *
from snake_init import *
global clock
clock = pygame.time.Clock()
global window
global IMAGE_SET
IMAGE_SET = {}#set named, map however
global WINDOW_X, WINDOW_Y
WINDOW_X = 800
WINDOW_Y = 600
global SCALE
SCALE = 30
global RED, GREEN, BLUE, BLACK, WHITE
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
global fps#暂无意义
def cls():
window.fill(BLACK)
def drawText(textContent, xpix, ypix, textSize = 30, textColor = WHITE):
textFont = pygame.font.SysFont(TEXT_FONT, textSize)
textSurface = textFont.render(textContent, False, textColor)
window.blit(textSurface, (xpix, ypix))
def drawImage(img, xpixleft, ypixup):
window.blit(img, (xpixleft, ypixup) )
def checkQuitEvent(event):
if event.type == pygame.QUIT:
sys.exit()
def getOppositeDirection(direction):
if direction == 'U': return 'D'
elif direction == 'D': return 'U'
elif direction == 'L': return 'R'
elif direction == 'R': return 'L'
class Train():
def __init__(self, initNode = (0, 0), moveDirection = 'R'):
self.nodes = [ (initNode) ]
self.moveDirection = moveDirection
self.length = 1
self.power = INIT_POWER
def addNode(self):
headNode = self.nodes[self.length - 1]
if self.moveDirection == 'U': self.nodes.append( (headNode[0], headNode[1] - 1) )
elif self.moveDirection == 'D': self.nodes.append( (headNode[0], headNode[1] + 1) )
elif self.moveDirection == 'L': self.nodes.append( (headNode[0] - 1, headNode[1]) )
elif self.moveDirection == 'R': self.nodes.append( (headNode[0] + 1, headNode[1]) )
self.length += 1
def delNode(self):
node = self.nodes[0]
del self.nodes[0]
self.length -= 1
return node
def drawTrain(self):
#绘制车头,朝向同运动方向
drawImage(IMAGE_SET['train-head-' + self.moveDirection], self.nodes[self.length - 1][0] * SCALE, self.nodes[self.length - 1][1] * SCALE)
#有车尾时绘制车尾
if self.length >= 2:
drawImage(IMAGE_SET['train-head-' + self.judgeRelaPos(self.nodes[0], self.nodes[1])], self.nodes[0][0] * SCALE, self.nodes[0][1] * SCALE )
#有车身时绘制车身
if self.length >= 3:
for index in xrange(1, self.length - 1):
relForward = self.judgeRelaPos(self.nodes[index], self.nodes[index + 1])
relBackward = self.judgeRelaPos(self.nodes[index], self.nodes[index - 1])
imgType = ''
if relForward in 'LR' and relBackward in 'LR':
imgType = 'train-body-LR-straight'
elif relForward in 'UD' and relBackward in 'UD':
imgType = 'train-body-UD-straight'
elif (relForward in 'LD' and relBackward in 'LD') or (relForward in 'RU' and relBackward in 'RU'):
imgType = 'train-body-DR-UL-curly'
elif (relForward in 'RD' and relBackward in 'RD') or (relForward in 'LU' and relBackward in 'LU'):
imgType = 'train-body-DL-UR-curly'
drawImage(IMAGE_SET[imgType], self.nodes[index][0] * SCALE, self.nodes[index][1] * SCALE)
def judgeRelaPos(self, d, s):
#判断d关于s的方位,要求s、d相邻
#s、d均为node
if s[0] == d[0]:
if s[1] == d[1] + 1: return 'U'
return 'D'
elif s[0] == d[0] + 1: return 'L'
return 'R'
'''
class Node():
def __init__(self, xpos, ypos):
self.xpos = xpos
self.ypos = ypos
'''
#列车碰撞一个乘客时,并不是清除该实例并创建一个新实例,而是将原实例位置刷新“视为”一个新实例
class Passenger():
def __init__(self):
self.xpos = 0
self.ypos = 0
def spawnNewPos(self):
self.xpos = randint(0, 19)
self.ypos = randint(0, 19)
def checkSpawnCollision(self, train):
#检验乘客生成时是否与列车重合
return (self.xpos, self.ypos) in train.nodes
def drawPassenger(self):
drawImage(IMAGE_SET['passenger'], self.xpos * SCALE, self.ypos * SCALE)
class Map():
def __init__(self, mapType = 0):
with open('map' + os.sep + str(mapType) + '.dat', 'rU') as file:
self.specBlocks = []
specBlocks = file.readlines()
for item in specBlocks:
block = item.split(' ')
self.specBlocks.append( Block(int(block[0]), int(block[1]), int(block[2])) )
def rechargeBlocksIfReady(self):
for block in self.specBlocks:
block.rechargeIfReady()
def drawMap(self):
for block in self.specBlocks:
block.drawBlock()
#对于空地不做记录,仅记录非空地的格子
class Block():
def __init__(self, type, xpos, ypos):
self.type = type
self.xpos = xpos
self.ypos = ypos
self.isCharged = True
self.lastDischargeTime = 0
def discharge(self):
self.isCharged = False
self.lastDischargeTime = default_timer()
def rechargeIfReady(self):
if default_timer() - self.lastDischargeTime >= CHARGE_TIME_COST:
self.isCharged = True
#print 'run'#debug
def drawBlock(self):
imgType = ''
if self.type == 1: imgType = 'railway-LR'
elif self.type == 2: imgType = 'railway-UD'
elif self.type == 3: imgType = 'railway-full'
if self.isCharged == True: imgType += '-powered'#充电的格子一律加'-powered'后缀
drawImage(IMAGE_SET[imgType], self.xpos * SCALE, self.ypos * SCALE)
#游戏主要有五个界面
class Game():
def __init__(self):
self.trainType = 0#0 for 和谐号(CRH), 1 for 复兴号(CR)
self.mapType = 0#0 for 吉安, 1 for 衡阳, 2 for 郑州
self.mode = 0#0 for 无限模式, 1 for 加急模式
self.fps = {0 : CRH_FPS, 1 : CR_FPS}
def showMainMenu(self):
cls()
pygame.display.update()
drawText(u'贪吃蛇', 250, 0, textSize = 100)
drawText(u'进入游戏(按r)', 250, 150, textSize = 50, textColor = RED)
drawText(u'查看排行(按f)', 250, 250, textSize = 50, textColor = GREEN)
drawText(u'退出程序(按v)', 250, 350, textSize = 50, textColor = BLUE)
pygame.display.update()
while True:
for event in pygame.event.get():
checkQuitEvent(event)#关闭窗口退出游戏
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:#r键进入关卡配置界面
self.showSelectMenu()
return
elif event.key == pygame.K_f:#f进入排行榜界面
self.showScorePage()
return
elif event.key == pygame.K_v:#v键退出游戏
sys.exit()
def showSelectMenu(self):
cls()
pygame.display.update()
self.trainType = 0
self.mapType = 0
self.mode = 0
chooseCur = 0
while True:
cls()
drawText(u'选择配置', 200, 0, textSize = 100)
drawText(u'依次输入相应配置对应的数字将选择对应的配置', 0, 100)
drawText(u'按y确认配置并进入游戏(未选择的配置视为自动选择第一项)', 0, 130)
drawText(u'车型:', 50, 200), drawText(u'和谐号0', 200, 200), drawText(u'复兴号1', 400, 200)
drawText(u'地图:', 50, 300), drawText(u'吉安0', 200, 300), drawText(u'衡阳1', 400, 300), drawText(u'郑州2', 600, 300)
drawText(u'模式:', 50, 400), drawText(u'无限模式0', 200, 400), drawText(u'加急模式1', 400, 400)
#游标指向,选择配置高亮
#chooseCur的有效值为0,1,2
if chooseCur in range(0, 3): drawText('=>', 0, 200 + chooseCur * 100)
if self.trainType == 0: drawText(u'和谐号0', 200, 200, textColor = RED)
else: drawText(u'复兴号1', 400, 200, textColor = RED)
if self.mapType == 0: drawText(u'吉安0', 200, 300, textColor = RED)
elif self.mapType == 1: drawText(u'衡阳1', 400, 300, textColor = RED)
else: drawText(u'郑州2', 600, 300, textColor = RED)
if self.mode == 0: drawText(u'无限模式0', 200, 400, textColor = RED)
else: drawText(u'加急模式1', 400, 400, textColor = RED)
pygame.display.update()
for event in pygame.event.get():
checkQuitEvent(event)#关闭窗口退出游戏
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_y:#确认选择进入游戏
self.showGamePage()
return
elif chooseCur == 0:#选择车型
chooseCur = 1
if event.key == pygame.K_0: self.trainType = 0#和谐号
elif event.key == pygame.K_1: self.trainType = 1#复兴号
elif chooseCur == 1:
chooseCur = 2
if event.key == pygame.K_0: self.mapType = 0
elif event.key == pygame.K_1: self.mapType = 1
elif event.key == pygame.K_2: self.mapType = 2
elif chooseCur == 2:
chooseCur = 0
if event.key == pygame.K_0: self.mode = 0
elif event.key == pygame.K_1: self.mode = 1
clock.tick(30)
def showGamePage(self):
#初始化开始
cls()
pygame.display.update()
#初始化参量,实例
score = 0
fps = self.fps[self.trainType]
map = Map(self.mapType)
train = Train()
passenger = Passenger()
passenger.spawnNewPos()
while passenger.checkSpawnCollision(train):
passenger.spawnNewPos()
#初始化视图界面
self.drawBar(score, train.power, 0)
map.drawMap()
train.drawTrain()
passenger.drawPassenger()
pygame.display.update()
#初始化计时器
allStartTimer = default_timer()
#载入音乐
pygame.mixer.music.load('music' + os.sep + 'express-run.mid')
pygame.mixer.music.play(-1)
#初始化完成
while True:
curStartTimer = default_timer()
fromDirection = getOppositeDirection(train.moveDirection)
map.rechargeBlocksIfReady()
#判断死亡
isDead = False
headNode = train.nodes[train.length - 1]
#车头撞其他部位,超出界限
if headNode in train.nodes[0: (train.length - 2)] or headNode[0] not in range(20) or headNode[1] not in range(20): isDead = True
#入轨判死
for block in map.specBlocks:
if headNode[0] == block.xpos and headNode[1] == block.ypos:
if (block.type == 1 and train.moveDirection in 'UD') or (block.type == 2 and train.moveDirection in 'LR'): isDead = True
if block.isCharged == True:
train.power += CHARGE_POWER
if train.power > MAX_POWER: train.power = MAX_POWER
block.discharge()
#监听事件,读取键盘输入执行对应转向操作
for event in pygame.event.get():
checkQuitEvent(event)#关闭窗口退出游戏
if event.type == pygame.KEYDOWN and train.power > 0:#列车断电后无法转向
toDirection = ''
if event.key == pygame.K_UP: toDirection = 'U'
elif event.key == pygame.K_DOWN: toDirection = 'D'
elif event.key == pygame.K_LEFT: toDirection = 'L'
elif event.key == pygame.K_RIGHT: toDirection = 'R'
if toDirection != '' and toDirection != fromDirection:
train.moveDirection = toDirection
#出轨判死,防止轨内非法方向运动
for block in map.specBlocks:
if headNode[0] == block.xpos and headNode[1] == block.ypos:
if (block.type == 1 and train.moveDirection in 'UD') or (block.type == 2 and train.moveDirection in 'LR'): isDead = True
if isDead == True:
drawText(u'道路千万条', 0, 140, textSize = 160, textColor = RED)
drawText(u'安全第一条', 0, 300, textSize = 160, textColor = RED)
pygame.display.update()
clock.tick(1)
if self.mode == 0: self.showDeathPage(score)
elif self.mode == 1: self.showDeathPage(int(default_timer() - allStartTimer) )
pygame.mixer.music.fadeout(1)
return
#前进
train.addNode()
if train.power > 0: train.power -= 1
#判载(撞)人
if passenger.checkSpawnCollision(train) == False: #未碰撞
train.delNode()
else:
passenger.spawnNewPos()
while passenger.checkSpawnCollision(train):
passenger.spawnNewPos()
score += 1
#依次绘制地图,(刷新)列车,同时绘制状态栏
cls()
self.drawBar(score, train.power, allStartTimer)
map.drawMap()
train.drawTrain()
passenger.drawPassenger()
pygame.display.update()
clock.tick(fps)
#加急模式下判断完成任务
if self.mode == 1 and score >= MISSION_SCORE:
drawText(u'任务完成', 80, 220, textSize = 160, textColor = RED)
pygame.display.update()
clock.tick(1)
self.showDeathPage(int(default_timer() - allStartTimer), True)
pygame.mixer.music.fadeout(1)
return
#print default_timer() - curStartTimer #debug
#补齐帧率
if default_timer() - curStartTimer < (1 / fps):
sleep(1 / fps - (default_timer() - curStartTimer) )
#print default_timer() - curStartTimer #debug
def showDeathPage(self, score, isMissionDone = False):
#显示死亡信息属于showGamePage的职能,此函数只负责死亡后跳转到的登记得分页面相关内容
cls()
pygame.display.update()
with open('scores.dat', 'r+') as file:
scores = file.readlines()
startIndex = scores.index('#' + str(self.trainType) + str(self.mapType) + str(self.mode) + '\n')
endIndex = len(scores) - 1#对于#121配置,恰好设置文件末的空行对应endIndex
for item in scores[(startIndex + 1) :]:
if item[0] == '#':
endIndex = scores.index(item)
break
curIndex = endIndex
isCurChanged = False
isfull = bool( (endIndex - startIndex) == 6 )
#当当前配置下数据未满时,平行的成绩应当被登记;反之不登记
for item in scores[(endIndex - 1) : startIndex: -1]:
if ( self.mode == 0 and score + (not isfull) > int(item.split(',')[0]) ) or ( self.mode == 1 and score - (not isfull) < int(item.split(',')[0][:(len(item.split(',')[0]) - 2 )] )):
curIndex = scores.index(item)
isCurChanged = True
#加急模式下,任务完成才可计入排行
if (self.mode == 0 or isMissionDone == True) and (isCurChanged == True or isfull == False):#本次数据达到插入条件
#按格式生成当前时间
dateTime = datetime.now()
curMinute = str(dateTime.minute)#str
if len(curMinute) == 1: curMinute = '0' + curMinute
currentTime = str(dateTime.year) + '/' + str(dateTime.month) + '/' + str(dateTime.day) + ' ' + str(dateTime.hour) + ':' + curMinute
#插入本次游戏数据至排行
if self.mode == 0: scores.insert(curIndex, str(score) + ',' + currentTime + '\n')
elif self.mode == 1: scores.insert(curIndex, str(score) + 's,' + currentTime + '\n')
if isfull == True: del scores[endIndex]#数据量溢出时删除当前最差数据
drawText(u'您本次的成绩刷新了排行情况!', 200, 300, textColor = RED)
with open('scores.dat', 'w') as file:
file.writelines(scores)
#print scores#debug
#显示提示内容,等待返回主界面
if self.mode == 0: drawText(u'本次成绩:%s' % str(score), 200, 250)
elif self.mode == 1: drawText(u'本次成绩:%ss' % str(score), 200, 250)
drawText(u'按n返回主界面', 200, 350)
pygame.display.update()
while True:
for event in pygame.event.get():
checkQuitEvent(event)#关闭窗口退出游戏
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_n:#回到主界面
return
def showScorePage(self):
#对于每种配置,只记录前五的分数
cls()
pygame.display.update()
with open('scores.dat', 'rU') as file:
scores = file.read().split('#')
for index in xrange(len(scores) ): scores[index] = scores[index].split('\n')
#如是得到一个二维列表,scores[0][i]无意义,scores[i(i!=0)][0]指示配置
self.trainType = 0
self.mapType = 0
self.mode = 0
chooseCur = 0
#print scores#debug
while True:
cls()
drawText(u'选择配置', 200, 0, textSize = 100)
drawText(u'依次输入相应配置对应的数字将选择对应的配置', 0, 100)
drawText(u'根据所选配置自动显示对应得分排行数据', 0, 130)
drawText(u'按n回到主界面', 0, 160)
drawText(u'车型:', 50, 200), drawText(u'和谐号0', 200, 200), drawText(u'复兴号1', 400, 200)
drawText(u'地图:', 50, 230), drawText(u'吉安0', 200, 230), drawText(u'衡阳1', 400, 230), drawText(u'郑州2', 600, 230)
drawText(u'模式:', 50, 260), drawText(u'无限模式0', 200, 260), drawText(u'加急模式1', 400, 260)
drawText(u'位次', 0, 300), drawText(u'时间', 100, 300), drawText(u'成绩', 500, 300)
#游标指向,选择配置高亮
#chooseCur的有效值为0,1,2
if chooseCur in range(0, 3): drawText('=>', 0, 200 + chooseCur * 30)
if self.trainType == 0: drawText(u'和谐号0', 200, 200, textColor = RED)
else: drawText(u'复兴号1', 400, 200, textColor = RED)
if self.mapType == 0: drawText(u'吉安0', 200, 230, textColor = RED)
elif self.mapType == 1: drawText(u'衡阳1', 400, 230, textColor = RED)
else: drawText(u'郑州2', 600, 230, textColor = RED)
if self.mode == 0: drawText(u'无限模式0', 200, 260, textColor = RED)
else: drawText(u'加急模式1', 400, 260, textColor = RED)
indexCur = 1 + self.trainType * 6 + self.mapType * 2 + self.mode
for index in xrange(1, len(scores[indexCur]) - 1):
#if not scores[indexCur][index]: continue#舍去split()产生的''项
ypix = 300 + 50 * index
drawText(str(index), 0, ypix)
drawText(scores[indexCur][index].split(',')[1], 100, ypix)#日期在左
drawText(scores[indexCur][index].split(',')[0], 500, ypix)#成绩在右
pygame.display.update()
for event in pygame.event.get():
checkQuitEvent(event)#关闭窗口退出游戏
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_n:#回到主界面
return
elif chooseCur == 0:#选择车型
chooseCur = 1
if event.key == pygame.K_0: self.trainType = 0#和谐号
elif event.key == pygame.K_1: self.trainType = 1#复兴号
elif chooseCur == 1:
chooseCur = 2
if event.key == pygame.K_0: self.mapType = 0
elif event.key == pygame.K_1: self.mapType = 1
elif event.key == pygame.K_2: self.mapType = 2
elif chooseCur == 2:
chooseCur = 0
if event.key == pygame.K_0: self.mode = 0
elif event.key == pygame.K_1: self.mode = 1
clock.tick(30)
def drawBar(self, score, power, startTimer):
pygame.draw.rect(window, WHITE, (600, 0, 20, 600), 0)
drawText('Score:', 630, 200)
drawText(str(score), 630, 240)
textColor = GREEN
split_max_power = MAX_POWER / 3
drawText('Power:', 630, 300)
if split_max_power < power <= (split_max_power * 2): textColor = WHITE
elif 0 <= power <= split_max_power: textColor = RED
drawText(str(power), 630, 340, textColor = textColor)
if self.mode == 1:
drawText('Time:', 630, 400)
drawText(str(int(default_timer() - startTimer) ) + 's', 630, 440)
if __name__ == '__main__':
#将工作路径切换到脚本所在路径,确保其他文件能正常读取
os.chdir(sys.path[0])
pygame.init()
for fileName in os.listdir('image'):
IMAGE_SET[fileName.split('.')[0] ] = pygame.image.load('image' + os.sep + '%s' % fileName)
window = pygame.display.set_mode( (WINDOW_X, WINDOW_Y), 0, 32)
game = Game()
while True:
game.showMainMenu()
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Python
1
https://gitee.com/greedy-snake-projectsets/Adapted-game-TrainSnake.git
git@gitee.com:greedy-snake-projectsets/Adapted-game-TrainSnake.git
greedy-snake-projectsets
Adapted-game-TrainSnake
TrainSnake
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891