兔子与獾本是国外12岁小孩用pygame写的游戏,这里我做了一些修改,加强了可玩性和娱乐性
游戏介绍
先介绍以下游戏背景。
最近有一种游戏非常火爆,叫做“养鲲游戏”,其实就是一些也有广告,游戏本身并没有这些鲲的存在。广告效果是这样的,画风还不错,决定用这个素材做一下。
具有灰暗画风的还是作为反派吧,现在需要一个可爱画风又有正义感的正面人物。于是我想到了我所处的城市——无锡,无锡有名的当然是“太湖神鼋啊”,于是英雄也有了。而英雄的素材,一定要经典,让人印象深刻,还不能过于浮夸。于是我就想到了他
请忽略上面的马里奥,其实他们是好朋友。
--------------------以上是游戏背景--------------------
下面介绍以下游戏的玩法。
wasd上下左右,鼠标射击,击杀20个敌人后屏幕上会随机出现双箭的标志,走过去可以升级武器,伤害加倍,判定范围加倍。 每击杀30敌人,屏幕左上角会出现手握雷电的标志,按下f键,会自动杀死两个左右的敌人,技能数量可以积累。前期的怪都会很小,后期的怪会变大,血量也比小怪厚很多,另外增设了一个boss的角色。但是这样的游戏还是太老套,对于玩家来说打赢游戏还是轻而易举的。所以添加了个不确定因素,在地图中随机存放了三个地雷,在移动、捡装备过程中也可能就会gameover。
1.首先我们定义鲲类 放在badguy.py里
import pygame
from pygame.locals import *
from random import randint
class Badguy(pygame.sprite.Sprite): # 继承pygame的Sprite类
def __init__(self, initial_position, filename="resources/images/01.png", speed=1, health=1, scale=1):
pygame.sprite.Sprite.__init__(self)
self.scale = scale
self.image = pygame.image.load(filename)
if self.scale == 2: # 对于图片素材2倍扩展
self.image = pygame.transform.scale2x(pygame.image.load(filename))
if self.scale == 3:
self.image = pygame.transform.scale(pygame.image.load(filename), (3*64, 3*29))
self.rect = self.image.get_rect()
self.rect.topleft = initial_position
self.speed = speed
self.health = health # 生命值
def move(self): # 让鲲移动
self.rect.left = self.rect.left - self.speed
2.因为捡到武器之后会得到双箭,所以要对武器进行抽象,定义武器类weapon.py
import pygame
class Weapon(pygame.sprite.Sprite):
def __init__(self, filename="resources/images/bullet.png", hit=1, vex=[], channel=1):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(filename)
self.rect = self.image.get_rect()
self.hit = hit # 伤害值
self.vex = vex # 发射角度[x,y]
self.channel = channel # 默认为单箭,升级后channel=2
3.还要定义个地雷类,还要设定踩到雷之后触发雷的爆炸效果
import pygame
class Mine(pygame.sprite.Sprite):
def __init__(self, initial_position, filename="resources/images/bomb.png"):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.transform.scale2x(pygame.image.load(filename))
self.tempImg = pygame.transform.scale(self.image, (172//5, 34))
self.rect = self.tempImg.get_rect()
self.rect.topleft = initial_position
self.size = self.image.get_size()
self.show_size_x, self.show_size_y = (self.size[0] // 5, self.size[1])
self.frame_no = 0
def show(self):
# 通过帧的切换实现雷的爆炸效果
self.frame_no += 1
self.frame_no %= 5
pygame.time.delay(100)
# screen.blit(self.image, (0, 0), (self.frame_no * self.show_size_x, 0, self.show_size_x, self.show_size_y))
4.最后,game.py用while循环实现游戏的运行。(没有实现界面与逻辑分离也没有多线程处理)
from sys import exit
import pygame
from pygame.locals import *
import math
import random
from badguy import Badguy
from weapon import Weapon
from mine import Mine
# 2
# 初始化pygame,创建了一个窗口
pygame.init()
width, height = 900, 480
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("太湖神鼋VS巨型腐鲲")
keys = [False, False, False, False]
playerpos = [100, screen.get_rect().centery]
killNum = 0
arrows = []
# 定义一个定时器,使得游戏里可以经过一段时间后就新建一只鲲
badtimer = 90
badtimer1 = 0
# 定义游戏时间
playTime = 600000
#定义武器数量
WeaponGroup = pygame.sprite.Group()
isDoubleArrow = False
# 生成双箭武器
doubleArrow = pygame.image.load("resources/images/bulletDouble.png")
doubleArrowX, doubleArrowY = random.randint(200, width//2), random.randint(20, height-20)
doubleArrowRect = pygame.Rect(doubleArrow.get_rect())
doubleArrowRect.top = doubleArrowY
doubleArrowRect.left = doubleArrowX
rada = 0
popTime = 0 # 定义一次消灭敌人的个数,否则会因为快速循环删除很多敌人
# badguys 记录badguy的位置坐标的列表
badguy1 = Badguy((900, 100)) # 先实例化一个鲲,加入到BadguyGroup中
BadguyGroup = pygame.sprite.Group()
BadguyGroup.add(badguy1)
badNum = 0
Badspeed = 1
BadMidBoss = 5
BadBigBoss = 1
hasKilledBigBoss = False
BossHasReached = False
healthvalue = 194
pygame.mixer.init()
isOutofWindow = False
# 3
# 加载本地图片
player = pygame.image.load("resources/images/turtle.png")
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")
arrow = pygame.image.load("resources/images/bullet.png")
# 加载武器图片
radaImg = pygame.image.load("resources/images/rada.png")
# 加载鲲图片
badguyimg1 = pygame.image.load("resources/images/01.png")
badguyimg = badguyimg1
# 加载健康图片
healthbar = pygame.image.load("resources/images/healthbar.png")
health = pygame.image.load("resources/images/health.png")
# 加载输赢图片
gameover = pygame.image.load("resources/images/gameover.png")
youwin = pygame.image.load("resources/images/youwin.png")
# 加载声音
hit = pygame.mixer.Sound("resources/audio/explode.wav")
enemy = pygame.mixer.Sound("resources/audio/enemy.wav")
shoot = pygame.mixer.Sound("resources/audio/shoot.wav")
bomb = pygame.mixer.Sound("resources/audio/bomb.wav")
thunder = pygame.mixer.Sound("resources/audio/thunder.wav")
gain = pygame.mixer.Sound("resources/audio/gain.wav")
warning = pygame.mixer.Sound("resources/audio/warning.wav")
fail = pygame.mixer.Sound("resources/audio/fail.wav")
success = pygame.mixer.Sound("resources/audio/success.wav")
# 调节声音大小
hit.set_volume(0.1)
enemy.set_volume(0.1)
shoot.set_volume(0.03)
bomb.set_volume(0.2)
warning.set_volume(0.2)
thunder.set_volume(0.08)
gain.set_volume(0.2)
success.set_volume(0.4)
fail.set_volume(0.4)
pygame.mixer.music.load('resources/audio/moonlight.wav')
pygame.mixer.music.play(-1, 0.0)
pygame.mixer.music.set_volume(0.15)
# 生成地雷
hasSteppedMine = False
minesPositions = [[random.randint(200, width-20), random.randint(20, height-20)] for i in range(3)]
MineGroup = pygame.sprite.Group()
for mineposition in minesPositions:
mine = Mine(mineposition)
MineGroup.add(mine)
# print(minesPositions)
time = 10
# 4
# 进入循环
running = 1
exitcode = 0
while running:
if popTime > 0:
print(popTime)
badtimer -= 1
badspeed = Badspeed # 重新初始化坏蛋速度
# 5 设置黑色背景
screen.fill(0)
# 6
# 循环画上背景
for x in range(width // grass.get_width() + 1):
for y in range(height // grass.get_height() + 1):
screen.blit(grass, (x * 100, y * 100))
# 画上四个城堡
screen.blit(castle, (0, 30))
screen.blit(castle, (0, 135))
screen.blit(castle, (0, 240))
screen.blit(castle, (0, 345))
# 画上小兔子
# 玩家旋转兔子
position = pygame.mouse.get_pos()
angle = math.atan2(position[1] - (playerpos[1] + 32), position[0] - (playerpos[0] + 26))
playerrot = pygame.transform.rotate(player, 360 - angle * 57.29)
playerpos1 = (playerpos[0] - playerrot.get_rect().width // 2, playerpos[1] - playerrot.get_rect().height // 2)
screen.blit(playerrot, playerpos1)
playerrect = pygame.Rect(player.get_rect())
playerrect.top = playerpos1[1]
playerrect.left = playerpos1[0]
# 双箭武器升级
if killNum >= 20 and not isDoubleArrow:
screen.blit(doubleArrow, (doubleArrowX, doubleArrowY))
if doubleArrowRect.colliderect(playerrect):
gain.play()
isDoubleArrow = True
# 触碰雷区
for mine in MineGroup.sprites():
if mine.rect.colliderect(playerrect):
hasSteppedMine = True
bomb.play()
break
if hasSteppedMine:
while time > 0:
for mine in MineGroup.sprites():
mine.show()
screen.blit(mine.image, mine.rect, (mine.frame_no * mine.show_size_x, 0, mine.show_size_x, mine.show_size_y))
pygame.display.update(mine.rect)
time -= 1
# 画出箭头
for bullet in WeaponGroup.sprites():
index = 0
velx = math.cos(bullet.vex[0]) * 10
vely = math.sin(bullet.vex[0]) * 10
bullet.vex[1] += velx
bullet.vex[2] += vely
if bullet.vex[1] < -64 or bullet.vex[1] > 900 or bullet.vex[2] < -64 or bullet.vex[2] > 480:
WeaponGroup.remove(bullet)
index += 1
for projectile in WeaponGroup.sprites():
arrow1 = pygame.transform.rotate(bullet.image, 360 - projectile.vex[0] * 57.29)
screen.blit(arrow1, (projectile.vex[1], projectile.vex[2]))
# 画上鲲
if badtimer == 0:
if BadBigBoss > 0:
n = random.randint(0, 30)
if n == 2 or n == 3:
badspeed = n
badguy = Badguy([900, random.randint(50, 430)], speed=badspeed)
BadguyGroup.add(badguy)
badNum += 1
if killNum > 80 and BadMidBoss > 0: # 杀死50个敌人 会出现5个中boss
MidBoss = Badguy([900, random.randint(50, 430)], speed=0.8, health=50, scale=2)
BadguyGroup.add(MidBoss)
BadMidBoss -= 1
badNum += 1
if killNum > 120 and BadBigBoss > 0: # 杀死80个敌人 会出现1个大boss
BigBoss = Badguy([900, random.randint(50, 400)], speed=0.5, health=200, scale=3)
BadguyGroup.add(BigBoss)
BadBigBoss -= 1
badNum += 1
warning.play()
# 加载boss血条
bosshealthbar = pygame.transform.scale(healthbar, (400, 30))
bosshealth = pygame.transform.scale(health, (4, 25))
badtimer = 100 - (badtimer1 * 2)
if badtimer1 >= 35:
badtimer1 = 35
else:
badtimer1 += 2
try:
if BigBoss in BadguyGroup.sprites():
screen.blit(bosshealthbar, (200, 60))
for health1 in range(BigBoss.health*2):
screen.blit(bosshealth, (health1 + 198, 62))
except:
pass
index = 0
for badguy in BadguyGroup.sprites():
if badguy.rect.left < -64:
BadguyGroup.remove(badguy)
badguy.move()
# print(badguy.rect.left, badguy.rect.top)
# 鲲冲过来并且在碰到城堡的时候会消失。尽管你看不到,鲲实际上会降低你的健康值。
badrect = pygame.Rect(badguyimg.get_rect())
badrect.top = badguy.rect.top
badrect.left = badguy.rect.left
if badrect.left < 64:
hit.play()
hitvalue = random.randint(1 * int((badguy.speed**2 + 1)), 3 * int((badguy.speed**2+1))) * badguy.health
healthvalue -= hitvalue
print(hitvalue)
BadguyGroup.remove(badguy)
try:
if badguy is BigBoss:
BossHasReached = True
except:
pass
# 检查箭头
index1 = 0
for bullet in WeaponGroup.sprites():
bullrect = pygame.Rect(bullet.image.get_rect())
bullrect.left = bullet.vex[1]
bullrect.top = bullet.vex[2]
# 检测箭头是否与坏蛋相交
if badrect.colliderect(bullrect):
badguy.health -= bullet.hit
if badguy.health <= 0:
enemy.play()
killNum += 1
try:
if badguy == BigBoss:
hasKilledBigBoss = True
break
except:
pass
if killNum > 0 and killNum % 30 == 0: # 杀死20个敌人获得一个雷达武器
rada += 1
popTime += 2
try:
BadguyGroup.remove(badguy)
except:
pass
try:
WeaponGroup.remove(bullet)
except:
pass
index1 += 1
index += 1
screen.blit(badguy.image, badguy.rect)
# 添加时钟用来计时
font = pygame.font.Font('resources/simsun.ttc', 18)
survivedtext = font.render("倒计时:" + str((playTime - pygame.time.get_ticks()) // 60000) + "分" + str((playTime - pygame.time.get_ticks()) // 1000 % 60).zfill(
2), True, (0, 0, 0))
textRect = survivedtext.get_rect()
textRect.topright = [width-30, 5]
screen.blit(survivedtext, textRect)
# 显示已杀死的敌人
font = pygame.font.Font('resources/simsun.ttc', 20)
killedtext = font.render(u"您已击杀" + str(killNum) + u"个敌人" .zfill(
2), True, (0, 0, 0))
textRect = killedtext.get_rect()
textRect.topright = [2*width//3, 5]
screen.blit(killedtext, textRect)
# 添加生命值显示
screen.blit(healthbar, (5, 5))
for health1 in range(healthvalue):
screen.blit(health, (health1 + 8, 8))
if rada > 0:
screen.blit(radaImg, (200, 3))
# 7
# 刷新屏幕
pygame.display.flip()
# 8设置游戏退出条件
for event in pygame.event.get():
if event.type == QUIT:
exit()
# 定义玩家wasd四个按键用来控制方向
if playerpos[0] > width - 10 or playerpos[0] < 10 or playerpos[1] < 10 or playerpos[1] > height-10:
isOutofWindow = True
if event.type == pygame.KEYDOWN and not isOutofWindow:
if event.key == K_w:
keys[0] = True
elif event.key == K_a:
keys[1] = True
elif event.key == K_s:
keys[2] = True
elif event.key == K_d:
keys[3] = True
if keys[0] and playerpos[1] > 10:
playerpos[1] -= 10
elif keys[2] and playerpos[1] < height - 10:
playerpos[1] += 10
elif keys[1] and playerpos[0] > 10:
playerpos[0] -= 10
elif keys[3] and playerpos[0] < width - 10:
playerpos[0] += 10
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
keys[0] = False
elif event.key == pygame.K_a:
keys[1] = False
elif event.key == pygame.K_s:
keys[2] = False
elif event.key == pygame.K_d:
keys[3] = False
# 雷达武器 一次消灭2个敌人,
if event.type == pygame.KEYDOWN:
if event.key == K_f and rada > 0:
rada -= 1
indx_1 = random.randint(0, len(BadguyGroup.sprites()))
indx_2 = random.randint(0, len(BadguyGroup.sprites()))
if event.type == pygame.KEYUP:
if event.key == K_f and popTime > 0:
try:
thunder.play()
popTime -= 2
BadguyGroup.sprites()[indx_1].health -= 1
BadguyGroup.sprites()[indx_2].health -= 1
if BadguyGroup.sprites()[indx_1].health <= 0:
BadguyGroup.remove(BadguyGroup.sprites()[indx_1])
killNum += 1
if BadguyGroup.sprites()[indx_2].health <= 0:
BadguyGroup.remove(BadguyGroup.sprites()[indx_2])
killNum += 1
except:
pass
# 跟踪箭头
if event.type == pygame.MOUSEBUTTONDOWN:
shoot.play()
position = pygame.mouse.get_pos()
vex = [math.atan2(position[1] - (playerpos1[1] + 32),
position[0] - (playerpos1[0] + 26)),
playerpos1[0] + 32,
playerpos1[1] + 32
]
# 装填武器
if killNum < 20 or not isDoubleArrow:
bullet = Weapon(vex=vex)
elif isDoubleArrow: # 双箭
bullet = Weapon(filename="resources/images/bulletDouble.png", vex=vex, hit=2, channel=2)
WeaponGroup.add(bullet)
# 检查输赢
if pygame.time.get_ticks() >= playTime or killNum >= 200 or hasKilledBigBoss:
running = 0
exitcode = 1
if healthvalue <= 0 or BossHasReached or hasSteppedMine:
running = 0
exitcode = 0
# 输赢显示
if exitcode == 0:
pygame.time.wait(500)
fail.play()
pygame.font.init()
font = pygame.font.Font("resources/simsun.ttc", 36) #设定中文字体
text = font.render(u"您击杀了: " + str(killNum) + u"敌人", True, (255, 0, 0))
textRect = text.get_rect()
gameover = pygame.transform.scale(gameover, (width, height))
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery + 40
screen.blit(gameover, (0, 0))
screen.blit(text, textRect)
else:
pygame.time.wait(500)
success.play()
pygame.font.init()
font = pygame.font.Font('resources/simsun.ttc', 36)
text = font.render(u"您击杀了: " + str(killNum) + u"敌人", True, (0, 255, 0))
textRect = text.get_rect()
youwin = pygame.transform.scale(youwin, (width, height))
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery + 50
screen.blit(youwin, (0, 0))
screen.blit(text, textRect)
if hasKilledBigBoss:
text1 = font.render("您已击杀巨型腐鲲! ", True, (0, 255, 0))
textRect1 = text1.get_rect()
textRect1.centerx = screen.get_rect().centerx
textRect1.centery = screen.get_rect().centery + 20
screen.blit(text1, textRect1)
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
pygame.display.flip()闪电侠的右手/兔子和獾gitee.com