3

pygame 和游戏编程的新手,只是想知道如何让相机在自上而下的汽车游戏中跟随汽车(没什么花哨的)——想想 Micro Machines!我正在使用 Python 3.6,并且有一辆自行车在旋转和四处走动。我已将此处的代码缩短了,但如果相机正常工作,我确实有一个静态图像供参考!

这是我所拥有的:

import pygame, math, sys, random
from pygame.locals import *

display_width = 1280
display_height = 800

# Sets size of screen
screen = pygame.display.set_mode((display_width, display_height))

# Initialises clock
clock = pygame.time.Clock()

# Colours
white = (255,255,255)
black = (0,0,0)

class Entity(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

class VehicleSprite(Entity):
    # Creates a vehicle class
    MAX_FORWARD_SPEED = 10
    MAX_REVERSE_SPEED = 2
    ACCELERATION = 0.05
    TURN_SPEED = 0.000000000001

    def __init__(self, image, position):
        Entity.__init__(self)

        # Creates object instance off
        pygame.sprite.Sprite.__init__(self)
        self.src_image = pygame.image.load(image)
        self.position = position
        self.speed = self.direction = 0
        self.k_left = self.k_right = self.k_down = self.k_up = 0


    def update(self, time):
        # SIMULATION
        self.speed += (self.k_up +self.k_down)
        if self.speed > self.MAX_FORWARD_SPEED:
            self.speed = self.MAX_FORWARD_SPEED
        if self.speed < -self.MAX_REVERSE_SPEED:
            self.speed = -self.MAX_REVERSE_SPEED

        # Degrees sprite is facing (direction)
        self.direction += (self.k_right + self.k_left)
        x, y = self.position
        rad = self.direction * math.pi / 180
        x += -self.speed*math.sin(rad)
        y += -self.speed*math.cos(rad)
        self.position = (x, y)
        self.image = pygame.transform.rotate(self.src_image, self.direction)
        self.rect = self.image.get_rect()
        self.rect.center = self.position

class Background(pygame.sprite.Sprite):
    def __init__(self, image_file, location):
        pygame.sprite.Sprite.__init__(self)  #call Sprite initializer
        self.image = pygame.image.load(image_file)
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = location

rect = screen.get_rect()

# Background
BackGround = Background('/home/pi/gametuts/images/backgrounds/bkg_img.png', [0, 0])

# Bike image load
bike = VehicleSprite('/home/pi/gametuts/images/BikePixelBig.png', rect.center)
bike_group = pygame.sprite.RenderPlain(bike)

# Ball image load
ball = VehicleSprite('/home/pi/gametuts/images/ironball.png', rect.center)
ball_group = pygame.sprite.RenderPlain(ball)

# Main game loop
def game_loop():

    while 1:
        #USER INPUT
        # Sets frame rate
        time = clock.tick(60)
        for event in pygame.event.get():
            if not hasattr(event, 'key'): continue
            down = event.type == KEYDOWN

            # Bike Input (Player 1)
            if event.key == K_d: bike.k_right = down * -5
            elif event.key == K_a: bike.k_left = down * 5
            elif event.key == K_w: bike.k_up = down * 2
            elif event.key == K_s: bike.k_down = down * -2      

            # Quit
            elif event.key == K_ESCAPE: sys.exit(0)

        #RENDERING

        # Game background
        screen.fill(white)
        screen.blit(BackGround.image, BackGround.rect)

        # Bike render
        bike_group.update(time)
        bike_group.draw(screen)

        ball_group.update(time)
        ball_group.draw(screen)

        pygame.display.flip()


game_loop()
pygame.quit()
quit()

提前致谢!

4

1 回答 1

3

实现相机的最简单方法是使用 apygame.math.Vector2作为相机,每帧从它减去玩家速度,然后将其添加到所有游戏元素的位置。

import pygame as pg
from pygame.math import Vector2


class Player(pg.sprite.Sprite):

    def __init__(self, pos, walls, *groups):
        super().__init__(*groups)
        self.image = pg.Surface((30, 50))
        self.image.fill(pg.Color('dodgerblue'))
        self.rect = self.image.get_rect(center=pos)
        self.vel = Vector2(0, 0)
        self.pos = Vector2(pos)
        self.walls = walls
        self.camera = Vector2(0, 0)

    def update(self):
        self.camera -= self.vel  # Change the camera pos if we're moving.
        # Horizontal movement.
        self.pos.x += self.vel.x
        self.rect.centerx = self.pos.x
        # Change the rect and self.pos coords if we touched a wall.
        for wall in pg.sprite.spritecollide(self, self.walls, False):
            if self.vel.x > 0:
                self.rect.right = wall.rect.left
            elif self.vel.x < 0:
                self.rect.left = wall.rect.right
            self.pos.x = self.rect.centerx
            self.camera.x += self.vel.x  # Also move the camera back.

        # Vertical movement.
        self.pos.y += self.vel.y
        self.rect.centery = self.pos.y
        for wall in pg.sprite.spritecollide(self, self.walls, False):
            if self.vel.y > 0:
                self.rect.bottom = wall.rect.top
            elif self.vel.y < 0:
                self.rect.top = wall.rect.bottom
            self.pos.y = self.rect.centery
            self.camera.y += self.vel.y


class Wall(pg.sprite.Sprite):

    def __init__(self, x, y, w, h, *groups):
        super().__init__(*groups)
        self.image = pg.Surface((w, h))
        self.image.fill(pg.Color('sienna2'))
        self.rect = self.image.get_rect(topleft=(x, y))


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()
    all_sprites = pg.sprite.Group()
    walls = pg.sprite.Group()
    for rect in ((100, 170, 90, 20), (200, 100, 20, 140),
                 (400, 60, 150, 100), (300, 470, 150, 100)):
        walls.add(Wall(*rect))
    all_sprites.add(walls)
    player = Player((320, 240), walls, all_sprites)

    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            elif event.type == pg.KEYDOWN:
                if event.key == pg.K_d:
                    player.vel.x = 5
                elif event.key == pg.K_a:
                    player.vel.x = -5
                elif event.key == pg.K_w:
                    player.vel.y = -5
                elif event.key == pg.K_s:
                    player.vel.y = 5
            elif event.type == pg.KEYUP:
                if event.key == pg.K_d and player.vel.x > 0:
                    player.vel.x = 0
                elif event.key == pg.K_a and player.vel.x < 0:
                    player.vel.x = 0
                elif event.key == pg.K_w and player.vel.y < 0:
                    player.vel.y = 0
                elif event.key == pg.K_s and player.vel.y > 0:
                    player.vel.y = 0

        all_sprites.update()

        screen.fill((30, 30, 30))
        for sprite in all_sprites:
            # Add the player's camera offset to the coords of all sprites.
            screen.blit(sprite.image, sprite.rect.topleft+player.camera)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()

编辑:这是您使用相机的代码示例。我还尝试改进了一些东西,例如max(min(...))限制速度值的技巧。我不确定运动是否如你所愿,但你当然可以自己调整。(我可能会对该update方法进行更多修改。)

import math
import random

import pygame


pygame.init()
screen = pygame.display.set_mode((1280, 800))
rect = screen.get_rect()
clock = pygame.time.Clock()

WHITE = pygame.Color('white')
# Load images globally and reuse them in your program.
# Also use the `.convert()` or `.convert_alpha()` methods after
# loading the images to improve the performance.
VEHICLE1 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE1.fill((130, 180, 20))
VEHICLE2 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE2.fill((200, 120, 20))
BACKGROUND = pygame.Surface((1280, 800))
BACKGROUND.fill((30, 30, 30))


class Entity(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)


class VehicleSprite(Entity):
    MAX_FORWARD_SPEED = 10
    MAX_REVERSE_SPEED = 2
    ACCELERATION = 0.05
    TURN_SPEED = 0.000000000001

    def __init__(self, image, position):
        Entity.__init__(self)
        self.src_image = image
        self.image = image
        self.rect = self.image.get_rect(center=position)
        self.position = pygame.math.Vector2(position)
        self.velocity = pygame.math.Vector2(0, 0)
        self.speed = self.direction = 0
        self.k_left = self.k_right = self.k_down = self.k_up = 0

    def update(self, time):
        # SIMULATION
        self.speed += self.k_up + self.k_down
        # To clamp the speed.
        self.speed = max(-self.MAX_REVERSE_SPEED,
                         min(self.speed, self.MAX_FORWARD_SPEED))

        # Degrees sprite is facing (direction)
        self.direction += (self.k_right + self.k_left)
        rad = math.radians(self.direction)
        self.velocity.x = -self.speed*math.sin(rad)
        self.velocity.y = -self.speed*math.cos(rad)
        self.position += self.velocity
        self.image = pygame.transform.rotate(self.src_image, self.direction)
        self.rect = self.image.get_rect(center=self.position)


class Background(pygame.sprite.Sprite):

    def __init__(self, image, location):
        pygame.sprite.Sprite.__init__(self)
        self.image = image
        self.rect = self.image.get_rect(topleft=location)


def game_loop():
    background = Background(BACKGROUND, [0, 0])
    bike = VehicleSprite(VEHICLE1, rect.center)
    ball = VehicleSprite(VEHICLE2, rect.center)

    bike_group = pygame.sprite.Group(bike)
    ball_group = pygame.sprite.Group(ball)
    all_sprites = pygame.sprite.Group(bike_group, ball_group)

    camera = pygame.math.Vector2(0, 0)
    done = False

    while not done:
        time = clock.tick(60)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True
            elif event.type == pygame.KEYDOWN:
                # Bike Input (Player 1)
                if event.key == pygame.K_d:
                    bike.k_right = -5
                elif event.key == pygame.K_a:
                    bike.k_left = 5
                elif event.key == pygame.K_w:
                    bike.k_up = 2
                elif event.key == pygame.K_s:
                    bike.k_down = -2

                elif event.key == pygame.K_ESCAPE:
                    done = True
            elif event.type == pygame.KEYUP:
                if event.key == pygame.K_d:
                    bike.k_right = 0
                elif event.key == pygame.K_a:
                    bike.k_left = 0
                elif event.key == pygame.K_w:
                    bike.k_up = 0
                elif event.key == pygame.K_s:
                    bike.k_down = 0

        camera -= bike.velocity

        all_sprites.update(time)

        screen.fill(WHITE)
        screen.blit(background.image, background.rect)

        for sprite in all_sprites:
            screen.blit(sprite.image, sprite.rect.topleft+camera)

        pygame.display.flip()


game_loop()
pygame.quit()
于 2017-07-30T20:25:49.927 回答