#python #pygame
#python #pygame
Вопрос:
ВИДЕО У меня есть базовый проигрыватель, перемещающийся по экрану, и у меня есть отображаемое изображение, которое я хочу использовать для наклона, когда мой проигрыватель находится на изображении, он может перемещаться так, как изображение, но у меня возникают проблемы с этим, потому что я использую прямоугольник, и я не уверен, чтокак это будет работать. есть ли способ, которым я мог бы заставить своего игрока двигаться как изображение наклона, а не просто двигаться прямо
мой код прямо сейчас, я только что сделал это, когда игрок сталкивается с моими наклонами, чтобы двигаться вперед, но как я могу улучшить его, чтобы он выглядел так, как будто он движется с наклоном изображения??
import pygame
pygame.init()
# make our screen for our game
window = pygame.display.set_mode((700,800))
# name our game
pygame.display.set_caption("Our Space Game")
class player:
def __init__(self,x,y,height,width,color):
self.x = x
self.y = y
self.height = height
self.width = width
self.color = color
# make our player jump
self.isJump = False
self.JumpCount = 10
self.fall = 0
self.rect = pygame.Rect(x,y,height,width)
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.rect)
white = (255,255,255)
playerman = player(200,200,10,10,white)
class slope():
def __init__(self,x,y,height,width,color):
self.x = x
self.y = y
self.height = height
self.width = width
self.color = color
self.image = pygame.image.load("hills1.png")
self.rect = pygame.Rect(x,y,height,width)
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.rect)
window.blit(self.image,self.rect)
slopes = []
platformGroup = pygame.sprite.Group
level = [
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" c "
]
for iy, row in enumerate(level):
for ix, col in enumerate(row):
if col == "c":
new_platforms = slope(ix*9.8, iy*50, 520,220,(23, 32, 42))
slopes.append(new_platforms)
# our game fps
fps = 40
clock = pygame.time.Clock()
def redraw():
window.fill((0,0,0))
playerman.draw()
for slope in slopes:
slope.draw()
# our game main loop
runninggame = True
while runninggame:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.quit:
runninggame = False
keys = pygame.key.get_pressed()
for slope in slopes:
if playerman.rect.colliderect(slope.rect):
playerman.x = 7
collide = False
if not playerman.isJump:
playerman.y = playerman.fall
playerman.fall = 1
playerman.isJump = False
collide = False
# collisions
for slope in slopes:
if playerman.rect.colliderect(slope.rect):
collide = True
playerman.isJump = False
playerman.y = slope.rect.top - playerman.height 1
if playerman.rect.right > slope.rect.left and playerman.rect.left < slope.rect.left - playerman.width:
playerman.x = slope.rect.left - playerman.width
if playerman.rect.left < slope.rect.right and playerman.rect.right > slope.rect.right playerman.width:
playerman.x = slope.rect.right
if playerman.rect.bottom >= 890:
collide = True
playerman.isJump = False
playerman.JumpCount = 10
playerman.y = 890 - playerman.height
if collide:
if keys[pygame.K_SPACE]:
playerman.isJump = True
playerman.fall = 0
else:
if playerman.JumpCount > 0:
playerman.y -= (playerman.JumpCount*abs(playerman.JumpCount)) * 0.3
playerman.JumpCount -= 1
else:
playerman.JumpCount = 10
playerman.isJump = False
redraw()
pygame.display.update()
pygame.quit()
мои спрайты
Комментарии:
1. Откуда вы взяли свое изображение? Похоже, это синусоидальная функция — у вас есть параметры?
Ответ №1:
Это вполне возможно, даже просто.
Я загрузил изображение «наклона» или земли и преобразовал его в массив numpy. После этого я нашел пиксели поверхности. Я использовал простое условие, чтобы определить, должен ли данный пиксель быть твердой поверхностью «воздуха»: если какой-либо из 4 каналов пикселя (= красный, зеленый, синий или альфа) больше нуля, этот пиксель считается твердой поверхностью. Если альфа-канал (последний) превышает некоторый порог, например 0 или 20, пиксель рассматривается как блок твердого грунта. Чтобы протестировать это, я сделал супер простой образец «игры», используя pygame. Игра загружает изображение в формате png (например, то, которое вы показали) и преобразует его.
Это решение использует одно и то же изображение как для обнаружения столкновений, так и для визуальных эффектов. Возможно, было бы неплохо добавить отдельный слой маски для столкновений вместо использования одного и того же файла. Если бы мы хотели использовать один и тот же файл, мы могли бы изменить контрастность и еще много чего, чтобы сделать изображение черно-белым, а затем применить к изображению какое-то определение границ.
ДЕМОНСТРАЦИЯ
Как это работает?
Допустим, у нас есть изображение, подобное этому, и мы хотим использовать его в качестве наклона. Это 8 пикселей в ширину и 5 пикселей в высоту. Я специально оставил там белый пиксель, поскольку на самом деле не имеет значения, что находится под поверхностью.
После того, как мы загрузили растровое изображение, оно выглядит следующим образом (у нас есть 2 канала для демонстрации, на самом деле не имеет значения, какие они — могут быть, например, интенсивность и альфа. На самом деле их было бы 4, для RGBA, но для демонстрации я выберу 2):
>>> from PIL import Image
>>> import numpy as np
>>> bitmap_original = Image.open("hills1.png")
>>> bitmap = np.array(bitmap_original)
array([[ [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0] ],
[ [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,1] ],
[ [0,0], [0,1], [0,1], [0,0], [0,0], [0,1], [0,1], [0,1] ],
[ [0,1], [0,1], [0,1], [0,1], [0,1], [0,1], [0,1], [0,1] ],
[ [0,1], [0,1], [0,1], [0,1], [0,1], [0,1], [0,0], [0,1] ]])
Я использовал изображение из PIL для загрузки изображения, это должно быть возможно сделать и с pygame.
Давайте превратим его в 2d-массив, содержащий только истинностные значения. Здесь нас интересует только последнее значение (которое является альфа-каналом в pngs).
>>> bitmap = bitmap[:,:,-1] > 0
array([[False, False, False, False, False, False, False, False],
[False, False, False, False, False, False, False, True],
[False, True, True, False, False, True, True, True],
[ True, True, True, True, True, True, True, True],
[ True, True, True, True, True, True, False, True]])
Затем, чтобы найти первое «True» из каждого столбца, мы можем транспонировать массив и пройти через каждый вектор в цикле for (есть и более быстрые способы сделать это …), И когда мы находим первое True, мы сохраняем местоположение в тепловой карте и переходим к следующему столбцу.
>>> bitmap_transposed = bitmap_2d.T
array([[False, False, False, True, True],
[False, False, True, True, True],
[False, False, True, True, True],
[False, False, False, True, True],
[False, False, False, True, True],
[False, False, True, True, True],
[False, False, True, True, False],
[False, True, True, True, True]])
Теперь массив готов, и мы можем легко выбрать значения y для каждого x.
for x, col in enumerate(bitmap_transposed):
for y, is_ground in enumerate(col): #
if is_ground:
self.height_map[x] = y
Я реализовал это так в примере игры:
from PIL import Image
import pygame as pg
import numpy as np
# Other code...
# This is called once during startup, possibly within a 'Game' class.
def img_to_map(self):
bitmap = np.array(self.bitmap)
# For each pixel: [0,0,0,0] => False, otherwise True
# bitmap = np.any(bitmap, axis=2)
# last element of each pixel value (= alpha) > 20 => True
bitmap = bitmap[:,:,-1] > 20
# initialize an empty array for the final height map
self.height_map = np.zeros(bitmap.shape[1], dtype=int)
for x, col in enumerate(bitmap.T): # bitmap's transpose
for y, is_ground in enumerate(col):
# First ground pixel found (=surface)! Save the location
# to the 'height map' and move to the next column.
if is_ground:
self.height_map[x] = int(y)
break
# Other code...
# This method can be used to get the surface height in given x coordinate,
# which can then be used to detect collisions with
# the ground, move a player vertically or whatever...
def height_at(self, x):
"""
Returns the ground height at given x coordinate.
Principle:
1. Check that the given coordinate lays somewhere within the ground.
2. The corresponding height value is available in the height map
that is generated during startup.
"""
# self.position is an object that holds the ground offset position
x_idx = x - self.position.x
# object is outside the slope, cannot collide
if x_idx < 0 or x_idx > (len(self.height_map) - 1):
return 0
# get the height value from the height map and add the ground offset value
return self.position.y self.height_map[x_idx]
# Other code...
Комментарии:
1. есть ли способ, которым я мог бы воспроизводить одно и то же изображение снова и снова, потому что я хочу, чтобы объект player продолжал двигаться в 1 направлении без остановки
2. кроме того, то, как вы это написали, для меня не имеет смысла, потому что мне нужен класс hell для повторения изображения, которое я создаю, как игра типа infinit run
3. что я пытаюсь сказать, как бы мне добавить еще один наземный объект проще, чем переделывать весь этот код
4. Да, конечно. Если бы я создавал бесконечный скроллер, я бы, вероятно, использовал какую-то сглаженную случайную функцию в качестве основной поверхности (тогда вам не нужно было бы выполнять какие-либо из этих операций с матрицей). Если бы я копировал одно и то же изображение, оно довольно быстро наскучило бы. Есть несколько способов обойти это. Возможно, используя что-то вроде этого .
5. Я отредактировал код, который вы мне прислали, и я пытаюсь сделать дублирование холмов, я поместил землю в виде списка, подобного этому,
ground = []
затем добавил это ИЗОБРАЖЕНИЕ , но я получаю много ошибок, не могли бы вы помочь мне с этим вот последний код: pastebin.com/raw/W9GYgWqL << У меня есть спрайт игрока для этоготак что вы, вероятно, не можете запустить его