玩家在预定路径上行走 [英] player walking on predetermined path pygame

查看:104
本文介绍了玩家在预定路径上行走的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是pygame的新手,我正在尝试制作一款游戏,玩家必须绕过某些敌人才能到达一个可以进入下一个关卡的地步。我需要敌人在预定的路径上来回走动,但我不知道该怎么做。所以我想知道是否有一种简单的方法?

I am new to pygame and I am trying to make a game where the player has to bypass some enemy's to get to a point where you can go to the next level. I need the enemy's to walk back and forward on a predetermined path but I can't figure out how to do it. So I was wondering if there is an easy way to do this?

这是我的代码。

import pygame
import random
import os
import time
from random import choices
from random import randint

pygame.init()
a = 0
b = 0
width = 1280
height = 720
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Game")
done = False
n = 0
x = 0
y = 0
x_wall = 0
y_wall = 0
clock = pygame.time.Clock()
WHITE = (255,255,255)
RED = (255,0,0)
change_x = 0
change_y = 0
HW = width / 2
HH = height / 2
background = pygame.image.load('mountains.png')

#player class
class Player(pygame.sprite.Sprite):
    def __init__(self):
      pygame.sprite.Sprite.__init__(self)
      self.image = pygame.image.load("character.png") 
      self.rect = self.image.get_rect()
      self.rect.x = width / 2
      self.rect.y = height / 2

#enemy class
class Enemy(pygame.sprite.Sprite):
  def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.image.load("enemy.png")
    self.image = pygame.transform.scale(self.image, (int(50), int(50)))
    self.rect = self.image.get_rect()
    self.rect.x = width / 3
    self.rect.y = height / 3

#wall class
class Wall(pygame.sprite.Sprite):
  def __init__(self, x, y):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.image.load("wall.png") 
    self.image = pygame.transform.scale(self.image, (int(50), int(50)))
    self.rect = self.image.get_rect()
    self.rect.x = x
    self.rect.y = y

#wall movement
  def update(self):
    self.vx = 0
    self.vy = 0
    key = pygame.key.get_pressed()
    if key[pygame.K_LEFT]:
      self.vx = 5
      self.vy = 0
    elif key[pygame.K_RIGHT]:
      self.vx = -5
      self.vy = 0
    if key[pygame.K_UP]:
      self.vy = 5
      self.vx = 0
    elif key[pygame.K_DOWN]:
      self.vy = -5
      self.vx = 0
    self.rect.x = self.rect.x + self.vx
    self.rect.y = self.rect.y + self.vy

#player sprite group
sprites = pygame.sprite.Group()
player = Player()
sprites.add(player)

#enemy sprite group
enemys = pygame.sprite.Group()
enemy = Enemy()
enemy2 = Enemy()
enemys.add(enemy, enemy2)

#all the wall sprites
wall_list = pygame.sprite.Group()
wall = Wall(x_wall, y_wall)
wall2 = Wall((x_wall + 50), y_wall)
wall3 = Wall((x_wall + 100), y_wall)
wall4 = Wall((x_wall + 150), y_wall)
wall5 = Wall((x_wall + 200), y_wall)
wall6 = Wall((x_wall + 250), y_wall)


#add all the walls to the list to draw them later
wall_list.add(wall, wall2, wall3, wall4, wall5, wall6)

#add all the walls here to fix the collision
all_walls = (wall, wall2, wall3, wall4, wall5, wall6)

while not done:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    sprites.update()
    wall_list.update()
    enemys.update()

    #collision between player and and walls
    if player.rect.collidelist(all_walls) >= 0:
      print("Collision !!")
      player.rect.x = player.rect.x - player.vx
      player.rect.y = player.rect.y - player.vx

    #fill the screen
    screen.fill((0, 0, 0))
    #screen.blit(background,(x,y))

    #draw the sprites
    sprites.draw(screen)
    wall_list.draw(screen)
    enemys.draw(screen)

    pygame.display.flip()
    clock.tick(60)

pygame.quit()

这是图像的下载链接如果要运行它:
https://geordyd.stackstorage.com/s/hZZ1RWcjal6ecZM

Here is the download link with the images if you want to run it: https://geordyd.stackstorage.com/s/hZZ1RWcjal6ecZM

推荐答案

我会给雪碧点列表( self.waypoints ),并将第一个分配给 self.target 属性。

I'd give the sprite a list of points (self.waypoints) and assign the first one to a self.target attribute.

update 方法中,我减去 self.pos self.target 位置获得指向目标且长度等于的向量(标题)到远方。将该向量缩放到所需的速度并将其用作速度(每帧将其添加到 self.pos 向量中),实体将朝目标移动。

In the update method I subtract the self.pos from the self.target position to get a vector (heading) that points to the target and has a length equal to the distance. Scale this vector to the desired speed and use it as the velocity (which gets added to the self.pos vector each frame) and the entity will move towards the target.

达到目标后,我只需增加航点索引并将列表中的下一个航点分配给 self.target 。当您接近目标时,放慢速度是个好主意,否则,如果精灵无法精确到达目标点,它可能会卡住并来回移动。因此,我还要检查精灵是否比 self.target_radius 更近,并将速度减小到最大速度的一部分。

When the target is reached, I just increment the waypoint index and assign the next waypoint in the list to self.target. It's a good idea to slow down when you're getting near the target, otherwise the sprite could get stuck and moves back and forth if it can't reach the target point exactly. Therefore I also check if the sprite is closer than the self.target_radius and decrease the velocity to a fraction of the maximum speed.

import pygame as pg
from pygame.math import Vector2


class Entity(pg.sprite.Sprite):

    def __init__(self, pos, waypoints):
        super().__init__()
        self.image = pg.Surface((30, 50))
        self.image.fill(pg.Color('dodgerblue1'))
        self.rect = self.image.get_rect(center=pos)
        self.vel = Vector2(0, 0)
        self.max_speed = 3
        self.pos = Vector2(pos)
        self.waypoints = waypoints
        self.waypoint_index = 0
        self.target = self.waypoints[self.waypoint_index]
        self.target_radius = 50

    def update(self):
        # A vector pointing from self to the target.
        heading = self.target - self.pos
        distance = heading.length()  # Distance to the target.
        heading.normalize_ip()
        if distance <= 2:  # We're closer than 2 pixels.
            # Increment the waypoint index to swtich the target.
            # The modulo sets the index back to 0 if it's equal to the length.
            self.waypoint_index = (self.waypoint_index + 1) % len(self.waypoints)
            self.target = self.waypoints[self.waypoint_index]
        if distance <= self.target_radius:
            # If we're approaching the target, we slow down.
            self.vel = heading * (distance / self.target_radius * self.max_speed)
        else:  # Otherwise move with max_speed.
            self.vel = heading * self.max_speed

        self.pos += self.vel
        self.rect.center = self.pos


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()
    waypoints = [(200, 100), (500, 400), (100, 300)]
    all_sprites = pg.sprite.Group(Entity((100, 300), waypoints))

    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True

        all_sprites.update()
        screen.fill((30, 30, 30))
        all_sprites.draw(screen)
        for point in waypoints:
            pg.draw.rect(screen, (90, 200, 40), (point, (4, 4)))

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


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

代替lis的航点我实际上更喜欢使用 itertools .cycle 并只需调用 next 切换到下一个点:

Instead of the waypoints list and index I'd actually prefer to use itertools.cycle and just call next to switch to the next point:

# In the `__init__` method.
self.waypoints = itertools.cycle(waypoints)
self.target = next(self.waypoints)

# In the `update` method.
if distance <= 2:
    self.target = next(self.waypoints)

这篇关于玩家在预定路径上行走的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆