ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Pygame学习笔记12:随机地形及Artillery Gunner游戏

2022-01-14 14:00:00  阅读:176  来源: 互联网

标签:12 self Artillery height player computer position shell Gunner


地形可以应用于许多不同的游戏中,因此这一章主要来学习构造地形,并且创造一个Artillery Gunner游戏。

Artillery Gunner游戏

首先需要再在MyLibrary.py中添加一些东西:

# 计算两点之间的距离
def distance(point1, point2):
    delta_x = point1.x - point2.x
    delta_y = point1.y - point2.y
    return math.sqrt(delta_x * delta_x + delta_y * delta_y)

然后,我们开始设计

地形的构造

对于地形类,我们是采用的随机构造,即首先固定第一个点,之后的点用random.randint()函数进行构造,但是如果只是简单的使用该函数处理,则可能会导致地形变化比较夸张,这不符合我们所熟知的地形,因此为了保证地形的连续性和渐变性,我们对其进行了更细致的处理:

# 地形类
class Terrain(object):
    def __init__(self, min_height, max_height, total_points):
        self.min_height = min_height
        self.max_height = max_height
        self.total_points = total_points + 1
        self.grid_size = 800 / total_points
        self.height_map = list()
        self.generate()

    def generate(self):
        # 首先清空列表
        if len(self.height_map) > 0:
            for n in range(self.total_points):
                self.height_map.pop()

        last_x = 0
        last_height = (self.max_height + self.min_height) / 2
        self.height_map.append(last_height)
        direction = 1
        run_length = 0

        # 保存点并且使得随机生成的点能够在一定可控的范围波动
        for n in range(1, self.total_points):
            rand_list = random.randint(1, 10) * direction
            height = last_height + rand_list
            self.height_map.append(int(height))
            if height < self.min_height:
                direction = -1
            elif height > self.max_height:
                direction = 1
            last_height = height
            if run_length <= 0:
                run_length = random.randint(1, 3)
                direction = random.randint(1, 2)
                if direction == 2:
                    direction = -1
            else:
                run_length -= 1

    def draw(self, surface):
        last_x = 0
        for n in range(1, self.total_points):
            height = 600 - self.height_map[n]
            x_pos = int(n * self.grid_size)
            pos = (x_pos, height)
            color = (255, 255, 255)
            # pygame.draw.circle(surface, color, pos, 4, 1)
            if n == grid_point:
                pygame.draw.circle(surface, (0, 255, 0), pos, 4, 0)
            last_height = 600 - self.height_map[n - 1]
            last_pos = (last_x, last_height)
            pygame.draw.line(surface, color, last_pos, pos, 2)
            last_x = x_pos

    def get_height(self, x):
        x_point = int(x / self.grid_size)
        return self.height_map[x_point]

初始化操作

游戏的一些初始化:

# 游戏的一些初始化操作
def game_init():
    global screen, backbuffer, font, timer, terrain
    pygame.init()
    screen = pygame.display.set_mode((800, 600))
    backbuffer = pygame.Surface((800, 600))
    pygame.display.set_caption("Artillery Gunner Game")
    font = pygame.font.Font(None, 30)
    timer = pygame.time.Clock()
    # 创造地形
    terrain = Terrain(50, 400, 100)

声音的相应加载:

# 用于初始化加载声音
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)

炮台的绘制

这里为了区分玩家的大炮和电脑的大炮,因此设计了两个函数,这两个函数类似,只是其中的一些细节有区别:

# 绘制玩家的大炮
def draw_player_cannon(surface, position):
    # 绘制炮台
    turret_color = (30, 180, 30)
    start_x = position.x + 15
    start_y = position.y + 15
    start_pos = (start_x, start_y)
    vel = angular_velocity(wrap_angle(player_cannon_angle - 90))
    end_pos = (start_x + vel.x * 30, start_y + vel.y * 30)
    pygame.draw.line(surface, turret_color, start_pos, end_pos, 6)
    # 绘制炮身
    body_color = (30, 220, 30)
    rect = Rect(position.x, position.y + 15, 30, 15)
    pygame.draw.rect(surface, body_color, rect, 0)
    pygame.draw.circle(surface, body_color, (position.x + 15, position.y + 15), 15, 0)


# 绘制电脑的大炮
def draw_computer_cannon(surface, position):
    # 绘制炮台
    turret_color = (180, 30, 30)
    start_x = position.x + 15
    start_y = position.y + 15
    start_pos = (start_x, start_y)
    vel = angular_velocity(wrap_angle(computer_cannon_angle - 90))
    end_pos = (start_x + vel.x * 30, start_y + vel.y * 30)
    pygame.draw.line(surface, turret_color, start_pos, end_pos, 6)
    # 绘制炮身
    body_color = (220, 30, 30)
    rect = Rect(position.x, position.y + 15, 30, 15)
    pygame.draw.rect(surface, body_color, rect, 0)
    pygame.draw.circle(surface, body_color, (position.x + 15, position.y + 15), 15, 0)

完整源代码

源代码如下:

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


# 地形类
class Terrain(object):
    def __init__(self, min_height, max_height, total_points):
        self.min_height = min_height
        self.max_height = max_height
        self.total_points = total_points + 1
        self.grid_size = 800 / total_points
        self.height_map = list()
        self.generate()

    def generate(self):
        # 首先清空列表
        if len(self.height_map) > 0:
            for n in range(self.total_points):
                self.height_map.pop()

        last_x = 0
        last_height = (self.max_height + self.min_height) / 2
        self.height_map.append(last_height)
        direction = 1
        run_length = 0

        # 保存点并且使得随机生成的点能够在一定可控的范围波动
        for n in range(1, self.total_points):
            rand_list = random.randint(1, 10) * direction
            height = last_height + rand_list
            self.height_map.append(int(height))
            if height < self.min_height:
                direction = -1
            elif height > self.max_height:
                direction = 1
            last_height = height
            if run_length <= 0:
                run_length = random.randint(1, 3)
                direction = random.randint(1, 2)
                if direction == 2:
                    direction = -1
            else:
                run_length -= 1

    def draw(self, surface):
        last_x = 0
        for n in range(1, self.total_points):
            height = 600 - self.height_map[n]
            x_pos = int(n * self.grid_size)
            pos = (x_pos, height)
            color = (255, 255, 255)
            # pygame.draw.circle(surface, color, pos, 4, 1)
            if n == grid_point:
                pygame.draw.circle(surface, (0, 255, 0), pos, 4, 0)
            last_height = 600 - self.height_map[n - 1]
            last_pos = (last_x, last_height)
            pygame.draw.line(surface, color, last_pos, pos, 2)
            last_x = x_pos

    def get_height(self, x):
        x_point = int(x / self.grid_size)
        return self.height_map[x_point]


# 游戏的一些初始化操作
def game_init():
    global screen, backbuffer, font, timer, terrain
    pygame.init()
    screen = pygame.display.set_mode((800, 600))
    backbuffer = pygame.Surface((800, 600))
    pygame.display.set_caption("Artillery Gunner Game")
    font = pygame.font.Font(None, 30)
    timer = pygame.time.Clock()
    # 创造地形
    terrain = Terrain(50, 400, 100)


# 用于初始化加载声音
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)


# 绘制玩家的大炮
def draw_player_cannon(surface, position):
    # 绘制炮台
    turret_color = (30, 180, 30)
    start_x = position.x + 15
    start_y = position.y + 15
    start_pos = (start_x, start_y)
    vel = angular_velocity(wrap_angle(player_cannon_angle - 90))
    end_pos = (start_x + vel.x * 30, start_y + vel.y * 30)
    pygame.draw.line(surface, turret_color, start_pos, end_pos, 6)
    # 绘制炮身
    body_color = (30, 220, 30)
    rect = Rect(position.x, position.y + 15, 30, 15)
    pygame.draw.rect(surface, body_color, rect, 0)
    pygame.draw.circle(surface, body_color, (position.x + 15, position.y + 15), 15, 0)


# 绘制电脑的大炮
def draw_computer_cannon(surface, position):
    # 绘制炮台
    turret_color = (180, 30, 30)
    start_x = position.x + 15
    start_y = position.y + 15
    start_pos = (start_x, start_y)
    vel = angular_velocity(wrap_angle(computer_cannon_angle - 90))
    end_pos = (start_x + vel.x * 30, start_y + vel.y * 30)
    pygame.draw.line(surface, turret_color, start_pos, end_pos, 6)
    # 绘制炮身
    body_color = (220, 30, 30)
    rect = Rect(position.x, position.y + 15, 30, 15)
    pygame.draw.rect(surface, body_color, rect, 0)
    pygame.draw.circle(surface, body_color, (position.x + 15, position.y + 15), 15, 0)


if __name__ == "__main__":
    game_init()
    audio_init()
    game_over = False
    player_score = 0
    enemy_score = 0
    last_time = 0
    mouse_x = mouse_y = 0
    grid_point = 0
    player_score = computer_score = 0
    player_cannon_position = Point(0, 0)
    player_cannon_angle = 45
    player_cannon_power = 8.0
    computer_cannon_position = Point(0, 0)
    computer_cannon_angle = 315
    computer_cannon_power = 8.0
    player_firing = False
    player_shell_position = Point(0, 0)
    player_shell_velocity = Point(0, 0)
    computer_firing = False
    computer_shell_position = Point(0, 0)
    computer_shell_velocity = Point(0, 0)

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

        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit()
            elif event.type == MOUSEMOTION:
                mouse_x, mouse_y = event.pos
            elif event.type == MOUSEBUTTONUP:
                terrain.generate()
        keys = pygame.key.get_pressed()
        if keys[K_ESCAPE]:
            sys.exit()
        # 上下键用于控制炮弹发射的角度
        elif keys[K_UP] or keys[K_w]:
            player_cannon_angle = wrap_angle(player_cannon_angle - 1)
        elif keys[K_DOWN] or keys[K_s]:
            player_cannon_angle = wrap_angle(player_cannon_angle + 1)
        # 左右键用于控制炮弹发射的力度
        elif keys[K_RIGHT] or keys[K_d]:
            if player_cannon_power <= 10.0:
                player_cannon_power += 0.1
        elif keys[K_LEFT] or keys[K_a]:
            if player_cannon_power >= 0.0:
                player_cannon_power -= 0.1
        # 玩家按下空格键发射炮弹
        if keys[K_SPACE]:
            if not player_firing:
                play_sound(shoot_sound)
                player_firing = True
                angle = wrap_angle(player_cannon_angle - 90)
                player_shell_velocity = angular_velocity(angle)
                player_shell_velocity.x *= player_cannon_power
                player_shell_velocity.y *= player_cannon_power
                player_shell_position = player_cannon_position
                player_shell_position.x += 15
                player_shell_position.y += 15

        if not game_over:
            # 保持炮台在一个合理的范围里
            if player_cannon_angle > 180:
                if player_cannon_angle < 270:
                    player_cannon_angle = 270
            elif player_cannon_angle <= 180:
                if player_cannon_angle > 90:
                    player_cannon_angle = 90

            # 计算鼠标在地形上的位置
            grid_point = int(mouse_x / terrain.grid_size)
            # 移动玩家的炮弹
            if player_firing:
                player_shell_position.x += player_shell_velocity.x
                player_shell_position.y += player_shell_velocity.y
                height = 600 - terrain.get_height(player_shell_position.x)
                # 炮弹是否击中地形
                if player_shell_position.y > height:
                    player_firing = False
                if player_shell_velocity.y < 10.0:
                    player_shell_velocity.y += 0.1
                # 若炮弹脱离屏幕,则消失
                if player_shell_position.x < 0 or player_shell_position.x > 800:
                    player_firing = False
                if player_shell_position.y < 0 or player_shell_position.y > 600:
                    player_firing = False

            # 移动电脑的炮弹
            if computer_firing:
                computer_shell_position.x += computer_shell_velocity.x
                computer_shell_position.y += computer_shell_velocity.y
                height = 600 - terrain.get_height(computer_shell_position.x)
                # 炮弹是否击中地形
                if computer_shell_position.y > height:
                    computer_firing = False
                if computer_shell_velocity.y < 10.0:
                    computer_shell_velocity.y += 0.1
                # 若炮弹脱离屏幕,则消失
                if computer_shell_position.x < 0 or computer_shell_position.x > 800:
                    computer_firing = False
                if computer_shell_position.y < 0 or computer_shell_position.y > 600:
                    computer_firing = False
            # 上一枚炮弹消失后则发射一枚新的炮弹
            else:
                play_sound(shoot_sound)
                computer_firing = True
                computer_cannon_power = random.randint(1, 10)
                angle = wrap_angle(computer_cannon_angle - 90)
                computer_shell_velocity = angular_velocity(angle)
                computer_shell_velocity.x *= computer_cannon_power
                computer_shell_velocity.y *= computer_cannon_power
                computer_shell_position = computer_cannon_position
                computer_shell_position.x += 15
                computer_shell_position.y += 15

            # 判断玩家的炮弹是否击中电脑的炮台
            if player_firing:
                dist = distance(player_shell_position, computer_cannon_position)
                if dist < 30:
                    play_sound(boom_sound)
                    player_score += 1
                    player_firing = False
            # 判断电脑的炮弹是否击中玩家的炮台
            if computer_firing:
                dist = distance(computer_shell_position, player_cannon_position)
                if dist < 30:
                    play_sound(boom_sound)
                    computer_score += 1
                    computer_firing = False

            backbuffer.fill((20, 20, 120))
            terrain.draw(backbuffer)
            # 绘制玩家的大炮
            y = 600 - terrain.get_height(70 + 15) - 20
            player_cannon_position = Point(70, y)
            draw_player_cannon(backbuffer, player_cannon_position)
            # 绘制电脑的大炮
            y = 600 - terrain.get_height(700 + 15) - 20
            computer_cannon_position = Point(700, y)
            draw_computer_cannon(backbuffer, computer_cannon_position)
            # 绘制玩家的炮弹
            if player_firing:
                x = int(player_shell_position.x)
                y = int(player_shell_position.y)
                pygame.draw.circle(backbuffer, (20, 230, 20), (x, y), 4, 0)
            # 绘制电脑的炮弹
            if computer_firing:
                x = int(computer_shell_position.x)
                y = int(computer_shell_position.y)
                pygame.draw.circle(backbuffer, (230, 20, 20), (x, y), 4, 0)
            screen.blit(backbuffer, (0, 0))
            if not game_over:
                print_text(font, 0, 0, "SCORE:" + str(player_score))
                print_text(font, 0, 20, "ANGLE:" + "{:.1f}".format(player_cannon_angle))
                print_text(font, 0, 40, "POWER:" + "{:.2f}".format(player_cannon_power))
                if player_firing:
                    print_text(font, 0, 60, "FIRING")
                print_text(font, 650, 0, "SCORE:" + str(computer_score))
                print_text(font, 650, 20, "ANGLE:" + "{:.1f}".format(computer_cannon_angle))
                print_text(font, 650, 40, "POWER:" + "{:.2f}".format(computer_cannon_power))
                if computer_firing:
                    print_text(font, 650, 60, "FIRING")
                print_text(font, 0, 580, "CURSOR:" + str(Point(mouse_x, mouse_y)) +
                           ", GRID POINT:" + str(grid_point) + ", HEIGHT:" + str(terrain.get_height(mouse_x)))
            else:
                print_text(font, 0, 0, "GAME OVER")

            pygame.display.update()


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

标签:12,self,Artillery,height,player,computer,position,shell,Gunner
来源: https://blog.csdn.net/weixin_55267022/article/details/122483116

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有