Pygame学习笔记11:三角函数及Tank Battle游戏

这一次将运用三角函数的相关知识以及前面学过的相关知识,如声音、精灵图像等来设计Tank Battle游戏,即坦克大战。

Tank Battle游戏

为了实现该游戏,需要再向MyLibrary.py文件中添加一些东西:

# 计算两个点之间的角度
def target_angle(x1, y1, x2, y2):
    delta_x = x2 - x1
    delta_y = y2 - y1
    angle_radians = math.atan2(delta_y, delta_x)
    angle_degrees = math.degrees(angle_radians)
    return angle_degrees


def angular_velocity(angle):
    vel = Point(0, 0)
    vel.x = math.cos(math.radians(angle))
    vel.y = math.sin(math.radians(angle))
    return vel

即用于实现旋转角度的一些函数

精灵类

涉及的精灵类有玩家坦克、敌方坦克和子弹类:

class Tank(MySprite):
    def __init__(self, tank_file="tank.png", turret_file="turret.png"):
        MySprite.__init__(self)
        self.load(tank_file, 50, 60, 4)
        self.speed = 0.0
        self.scratch = None
        self.float_pos = Point(0, 0)
        self.velocity = Point(0, 0)
        self.turret = MySprite()
        self.turret.load(turret_file, 32, 64, 4)
        self.fire_timer = 0

    def update(self, ticks):
        MySprite.update(self, ticks, 100)
        self.rotation = wrap_angle(self.rotation)
        self.scratch = pygame.transform.rotate(self.image, -self.rotation)
        angle = wrap_angle(self.rotation - 90)
        self.velocity = angular_velocity(angle)
        self.float_pos.x += self.velocity.x
        self.float_pos.y += self.velocity.y
        # 保证坦克会一直留在界面上
        if self.float_pos.x < -50:
            self.float_pos.x = 800
        elif self.float_pos.x > 800:
            self.float_pos.x = -50
        if self.float_pos.y < -60:
            self.float_pos.y = 600
        elif self.float_pos.y > 600:
            self.float_pos.y = -60

        self.X = int(self.float_pos.x)
        self.Y = int(self.float_pos.y)

        self.turret.position = (self.X, self.Y)
        self.turret.last_frame = 0
        self.turret.update(ticks, 100)
        self.turret.rotation = wrap_angle(self.turret.rotation)
        angle = self.turret.rotation + 90
        self.turret.scratch = pygame.transform.rotate(self.turret.image, -angle)

    def draw(self, surface):
        width, height = self.scratch.get_size()
        center = Point(width / 2, height / 2)
        surface.blit(self.scratch, (self.X - center.x, self.Y - center.y))
        # 绘制炮塔
        width, height = self.turret.scratch.get_size()
        center = Point(width / 2, height / 2)
        surface.blit(self.turret.scratch, (self.turret.X - center.x, self.turret.Y - center.y))

    def __str__(self):
        return MySprite.__str__(self) + ", " + str(self.velocity)


class EnemyTank(Tank):
    def __init__(self, tank_file="enemy_tank.png", turret_file="enemy_turret.png"):
        Tank.__init__(self, tank_file, turret_file)

    def update(self, ticks):
        self.turret.rotation = wrap_angle(self.rotation - 90)
        Tank.update(self, ticks)

    def draw(self, surface):
        Tank.draw(self, surface)


class Bullet(object):
    def __init__(self, position):
        self.alive = True
        self.color = (250, 20, 20)
        self.position = Point(position.x, position.y)
        self.velocity = Point(0, 0)
        self.rect = Rect(0, 0, 4, 4)
        self.owner = ""

    def update(self, ticks):
        self.position.x += self.velocity.x * 10.0
        self.position.y += self.velocity.y * 10.0
        if self.position.x < 0 or self.position.x > 800 or self.position.y < 0 or self.position.y > 600:
            self.alive = False
        self.rect = Rect(self.position.x, self.position.y, 4, 4)

    def draw(self, surface):
        pos = (int(self.position.x), int(self.position.y))
        pygame.draw.circle(surface, self.color, pos, 4, 0)

为了实现子弹类,还需要三个辅助函数用以实现双方坦克发射炮弹:

# 坦克发射炮弹
def fire_cannon(tank):
    position = Point(tank.turret.X, tank.turret.Y)
    bullet = Bullet(position)
    angle = tank.turret.rotation
    bullet.velocity = angular_velocity(angle)
    bullets.append(bullet)
    play_sound(shoot_sound)
    return bullet


# 玩家发射炮弹
def player_fire_cannon():
    bullet = fire_cannon(player)
    bullet.owner = "player"
    bullet.color = (30, 250, 30)


# 敌方发射炮弹
def enemy_fire_cannon():
    bullet = fire_cannon(enemy_tank)
    bullet.owner = "enemy"
    bullet.color = (250, 30, 30)

游戏初始化操作

# 游戏的一些初始化操作
def game_init():
    global screen, backbuffer, font, timer, player_group, player, enemy_tank, bullets, crosshair, crosshair_group
    pygame.init()
    screen = pygame.display.set_mode((800, 600))
    backbuffer = pygame.Surface((800, 600))
    pygame.display.set_caption("Tank Battle Game")
    font = pygame.font.Font(None, 30)
    timer = pygame.time.Clock()
    pygame.mouse.set_visible(False)
    # 加载鼠标光标
    crosshair = MySprite()
    crosshair.load("crosshair.png")
    crosshair_group = pygame.sprite.GroupSingle()
    crosshair_group.add(crosshair)
    # 创建玩家的坦克
    player = Tank()
    player.float_pos = Point(400, 300)
    # 创建敌方坦克
    enemy_tank = EnemyTank()
    enemy_tank.float_pos = Point(random.randint(50, 760), 50)
    enemy_tank.rotation = 135
    # 创建子弹精灵组
    bullets = list()

还有声音的相关函数:

# 用于初始化加载声音
def audio_init():
    global shoot_sound, boom_sound
    pygame.mixer.init()
    shoot_sound = pygame.mixer.Sound("shoot.wav")
    boom_sound = pygame.mixer.Sound("boom.wav")


# 播放声音
def play_sound(sound):
    channel = pygame.mixer.find_channel(True)
    channel.set_volume(0.5)
    channel.play(sound)

完整源代码

源代码如下:

import random
import sys
import pygame
from pygame.locals import *
from MyLibrary import *


class Tank(MySprite):
    def __init__(self, tank_file="tank.png", turret_file="turret.png"):
        MySprite.__init__(self)
        self.load(tank_file, 50, 60, 4)
        self.speed = 0.0
        self.scratch = None
        self.float_pos = Point(0, 0)
        self.velocity = Point(0, 0)
        self.turret = MySprite()
        self.turret.load(turret_file, 32, 64, 4)
        self.fire_timer = 0

    def update(self, ticks):
        MySprite.update(self, ticks, 100)
        self.rotation = wrap_angle(self.rotation)
        self.scratch = pygame.transform.rotate(self.image, -self.rotation)
        angle = wrap_angle(self.rotation - 90)
        self.velocity = angular_velocity(angle)
        self.float_pos.x += self.velocity.x
        self.float_pos.y += self.velocity.y
        # 保证坦克会一直留在界面上
        if self.float_pos.x < -50:
            self.float_pos.x = 800
        elif self.float_pos.x > 800:
            self.float_pos.x = -50
        if self.float_pos.y < -60:
            self.float_pos.y = 600
        elif self.float_pos.y > 600:
            self.float_pos.y = -60

        self.X = int(self.float_pos.x)
        self.Y = int(self.float_pos.y)

        self.turret.position = (self.X, self.Y)
        self.turret.last_frame = 0
        self.turret.update(ticks, 100)
        self.turret.rotation = wrap_angle(self.turret.rotation)
        angle = self.turret.rotation + 90
        self.turret.scratch = pygame.transform.rotate(self.turret.image, -angle)

    def draw(self, surface):
        width, height = self.scratch.get_size()
        center = Point(width / 2, height / 2)
        surface.blit(self.scratch, (self.X - center.x, self.Y - center.y))
        # 绘制炮塔
        width, height = self.turret.scratch.get_size()
        center = Point(width / 2, height / 2)
        surface.blit(self.turret.scratch, (self.turret.X - center.x, self.turret.Y - center.y))

    def __str__(self):
        return MySprite.__str__(self) + ", " + str(self.velocity)


class EnemyTank(Tank):
    def __init__(self, tank_file="enemy_tank.png", turret_file="enemy_turret.png"):
        Tank.__init__(self, tank_file, turret_file)

    def update(self, ticks):
        self.turret.rotation = wrap_angle(self.rotation - 90)
        Tank.update(self, ticks)

    def draw(self, surface):
        Tank.draw(self, surface)


class Bullet(object):
    def __init__(self, position):
        self.alive = True
        self.color = (250, 20, 20)
        self.position = Point(position.x, position.y)
        self.velocity = Point(0, 0)
        self.rect = Rect(0, 0, 4, 4)
        self.owner = ""

    def update(self, ticks):
        self.position.x += self.velocity.x * 10.0
        self.position.y += self.velocity.y * 10.0
        if self.position.x < 0 or self.position.x > 800 or self.position.y < 0 or self.position.y > 600:
            self.alive = False
        self.rect = Rect(self.position.x, self.position.y, 4, 4)

    def draw(self, surface):
        pos = (int(self.position.x), int(self.position.y))
        pygame.draw.circle(surface, self.color, pos, 4, 0)


# 坦克发射炮弹
def fire_cannon(tank):
    position = Point(tank.turret.X, tank.turret.Y)
    bullet = Bullet(position)
    angle = tank.turret.rotation
    bullet.velocity = angular_velocity(angle)
    bullets.append(bullet)
    play_sound(shoot_sound)
    return bullet


# 玩家发射炮弹
def player_fire_cannon():
    bullet = fire_cannon(player)
    bullet.owner = "player"
    bullet.color = (30, 250, 30)


# 敌方发射炮弹
def enemy_fire_cannon():
    bullet = fire_cannon(enemy_tank)
    bullet.owner = "enemy"
    bullet.color = (250, 30, 30)


# 游戏的一些初始化操作
def game_init():
    global screen, backbuffer, font, timer, player_group, player, enemy_tank, bullets, crosshair, crosshair_group
    pygame.init()
    screen = pygame.display.set_mode((800, 600))
    backbuffer = pygame.Surface((800, 600))
    pygame.display.set_caption("Tank Battle Game")
    font = pygame.font.Font(None, 30)
    timer = pygame.time.Clock()
    pygame.mouse.set_visible(False)
    # 加载鼠标光标
    crosshair = MySprite()
    crosshair.load("crosshair.png")
    crosshair_group = pygame.sprite.GroupSingle()
    crosshair_group.add(crosshair)
    # 创建玩家的坦克
    player = Tank()
    player.float_pos = Point(400, 300)
    # 创建敌方坦克
    enemy_tank = EnemyTank()
    enemy_tank.float_pos = Point(random.randint(50, 760), 50)
    enemy_tank.rotation = 135
    # 创建子弹精灵组
    bullets = list()


# 用于初始化加载声音
def audio_init():
    global shoot_sound, boom_sound
    pygame.mixer.init()
    shoot_sound = pygame.mixer.Sound("shoot.wav")
    boom_sound = pygame.mixer.Sound("boom.wav")


# 播放声音
def play_sound(sound):
    channel = pygame.mixer.find_channel(True)
    channel.set_volume(0.5)
    channel.play(sound)


if __name__ == "__main__":
    game_init()
    audio_init()
    game_over = False
    player_score = 0
    enemy_score = 0
    last_time = 0
    mouse_x = mouse_y = 0

    while True:
        timer.tick(30)
        ticks = pygame.time.get_ticks()

        mouse_up = mouse_down = 0
        mouse_up_x = mouse_up_y = 0
        mouse_down_x = mouse_down_y = 0

        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit()
            elif event.type == MOUSEMOTION:
                mouse_x, mouse_y = event.pos
                mov_x, mov_y = event.rel
            elif event.type == MOUSEBUTTONDOWN:
                mouse_down = event.button
                mouse_down_x, mouse_down_y = event.pos
            elif event.type == MOUSEBUTTONUP:
                mouse_up = event.button
                mouse_up_x, mouse_up_y = event.pos
        keys = pygame.key.get_pressed()
        if keys[K_ESCAPE]:
            sys.exit()
        # 左右键用于控制旋转
        elif keys[K_a] or keys[K_LEFT]:
            player.rotation -= 2.0
        elif keys[K_d] or keys[K_RIGHT]:
            player.rotation += 2.0
        # 按空格键或者按鼠标则发射炮弹
        if keys[K_SPACE] or mouse_up > 0:
            if ticks > player.fire_timer + 1000:
                player.fire_timer = ticks
                player_fire_cannon()

        if not game_over:
            crosshair.position = (mouse_x, mouse_y)
            crosshair_group.update(ticks)

        angle = target_angle(player.turret.X, player.turret.Y,
                             crosshair.X + crosshair.frame_width / 2,
                             crosshair.Y + crosshair.frame_height / 2)
        player.turret.rotation = angle

        player.update(ticks)
        enemy_tank.update(ticks)
        # 设置敌方坦克每隔1秒发射一枚炮弹
        if ticks > enemy_tank.fire_timer + 1000:
            enemy_tank.fire_timer = ticks
            enemy_fire_cannon()

        # 对每一枚炮弹做相应的处理
        for bullet in bullets:
            bullet.update(ticks)
            if bullet.owner == "player":
                if pygame.sprite.collide_rect(bullet, enemy_tank):
                    player_score += 1
                    bullet.alive = False
                    play_sound(boom_sound)
            elif bullet.owner == "enemy":
                if pygame.sprite.collide_rect(bullet, player):
                    enemy_score += 1
                    bullet.alive = False
                    play_sound(boom_sound)

        backbuffer.fill((100, 100, 20))
        for bullet in bullets:
            bullet.draw(backbuffer)
        enemy_tank.draw(backbuffer)
        player.draw(backbuffer)
        crosshair_group.draw(backbuffer)

        screen.blit(backbuffer, (0, 0))

        if not game_over:
            print_text(font, 0, 0, "PLAYER:" + str(player_score))
            print_text(font, 700, 0, "ENEMY:" + str(enemy_score))
        else:
            print_text(font, 0, 0, "G A M E O V E R")

        # 命中的子弹消失
        for bullet in bullets:
            if bullet.alive == False:
                bullets.remove(bullet)

        pygame.display.update()


运行结果如下:
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花无凋零之时

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值