전장 두꺼비 만들기 스크롤 배경 효과
35121 단어 gamedevprogrammingtutoriallua
Battletoads(1991) 터빈 터널층
나는 Pico-8의 원시 재창작을 하고 있다.그 불가사의한 유사점을 봐라.😉
다음은 실제 게임을 캡처한 것입니다.자세히 살펴보면 정령의 가장자리와 반복되는 곳을 볼 수 있다.나는 직사각형과 흰색 화살표로 몇 개의 점을 표시했다.
이것은 내가 만든 배경이며, 나의 정령이 어떻게 반복되는지 보여준다.
참고: 예는 Pico-8 Fantasy 콘솔에서 Lua를 사용하여 작성되었습니다.함수는 나의 해석과 관련된 코드 발췌문을 포함하는데, 반드시 완전한 코드는 아니다.
내가 모든 코드를 삭제하고 다른 일을 하기 전에, 내가 배경을 굴리는 최초의 사고 과정을 설명하는 것을 참을성 있게 들어 주십시오.
우선, 나는 모든 배경 부분에 단독 그룹을 만들기로 결정했다.배열은 화면의 너비를 덮어쓰기 위해 충분한 요소를 최소한으로 수용할 것이다.모든 원소는 정령의 너비, x1값(정령의 왼쪽 상단)과 x2값(정령의 오른쪽 상단)을 추적하는 대상이다.
내가 처음 통과했을 때, 나는 아래의 코드를 만들었다.
first_row
, second_row
등은 모두 표로 Lua에서 대상과 그룹을 만드는 데 사용되는 데이터 구조이다.init_bg()
에서, 나는 0에서 7로 순환해서,sprite 줄마다 표를 만들었다.add(first_row, { x1 = i * 16, w = 16, x2 = i * 16 + 16 })
값표를 first_row
표로 전송한다.7*16=112로 인해 마지막 정령의 x값은 112이고 이 정령의 x값은 16px로 게임 화면의 128px 너비를 덮어씁니다.32px 넓은 정령이 포함된 표에서 최종적으로 만들어진 정령의 수량은 화면을 덮어쓰는 데 필요한 수량을 초과하지만, 추가 화면 밖의 정령이 있는지 여부는 중요하지 않습니다.create_land()
비슷한 일을 했지만 10배로 순환했고 두 개의 표를 만들었다. 하나는 육지의 꼭대기에 사용되고 다른 하나는 밑에 사용된다.function _init()
-- speeds to control how fast each row is moving
top_bg_speed = 5
bottom_bg_speed = 6
middle_bg_speed = 1
land_speed = 5
-- tables for each row of sprites
first_row = {}
second_row = {}
land_top = {}
land_bottom = {}
third_row = {}
bottom_row = {}
init_bg()
end
function init_bg()
for i = 0, 7 do
add(first_row, create_spr_table(i, 16))
add(second_row, create_spr_table(i, 32))
add(third_row, create_spr_table(i, 32))
add(bottom_row, create_spr_table(i, 16))
end
create_land()
end
function create_spr_table(i, w)
return { x1 = i * w, w = w, x2 = i * w + w }
end
function create_land()
for i = 0, 10 do
add(land_top, create_spr_table(i, 32))
add(land_bottom, create_spr_table(i, 32))
end
end
30fps를 실행하는 _update()
함수에서, 나는 모든 표를 반복해서 새 x1
와 x2
값을 설정했다.줄마다 속도 변수가 있어 원하는 엘프가 굴러가는 속도에 따라 조정할 수 있습니다.전투의 두꺼비는 터빈 오토바이를 처음 탔을 때 전경과 배경의 정령이 조금씩 다른 속도로 움직이며 점차 올라간다. 똑같은 속도로 움직이는 것처럼 보인다. 속도가 너무 빨라 구분할 수 없기 때문이다.내 거야.gif에서 알 수 있듯이 나는 다른 속도를 유지했다. 왜냐하면 나는 이 효과를 좋아하기 때문이다. 그러나 나는 _init()
의 변수 값을 바꾸어 모든 부분을 같은 속도로 쉽게 운행할 수 있다.모든 요정이 왼쪽으로 이동할 때, 나는 요정이 언제 화면을 떠나는지 알아야 한다. 그러면 요정이 책상에서 제거될 수 있다.나는 시계마다 마지막 정령의
x2
값을 알아야 하기 때문에 새 정령을 시계에 밀어넣을 때 이 x2
값을 새 정령의 x1
값으로 사용할 수 있다.육상정령의 탁자는 다른 탁자와 달라야 한다. 끊임없이 반복되지 않기 때문에 스크린 밖에서 작동해야 한다.어떤 줄은 하나의 정령으로 구성되어 있으며, 그 중 하나의 시계의 순환을 사용하여 함께 업데이트된다.function _update()
-- only some rows are shown here, the rest are basically the same
-- update first row values
for i = 1, #first_row do
first_row[i].x1 -= top_bg_speed
set_new_x2(first_row, i)
end
-- update second/third row values
for i = 1, #second_row do
second_row[i].x1 -= middle_bg_speed
third_row[i].x1 -= middle_bg_speed
set_new_x2(second_row, i)
set_new_x2(third_row, i)
end
-- update land values
for i = 1, #land_top do
land_top[i].x1 -= land_speed
land_bottom[i].x1 -= land_speed
set_new_x2(land_top, i)
set_new_x2(land_bottom, i)
end
-- remove element once it goes out of view
if (is_offscreen_left(first_row[1].x2)) del_first_value(first_row)
if is_offscreen_left(second_row[1].x2) then
del_first_value(second_row)
del_first_value(third_row)
end
-- add element to end of table if there's an empty space between the last element x2 value and end of the game screen
if (should_add_bg_spr(first_row[#first_row].x2)) add_bg_spr_to_end(first_row, 16 )
if should_add_bg_spr(second_row[#second_row].x2) then
add_bg_spr_to_end(second_row, 32)
add_bg_spr_to_end(third_row, 32)
end
-- update land
if (is_offscreen_left(land_top[#land_top].x2)) reset_land()
end
function reset_land()
for i = 1, #land_top do
local start = i * 32 + 128
land_top[i].x1 = start
land_top[i].x2 = land_top[i].x1 + 32
land_bottom[i].x1 = start
land_bottom[i].x2 = land_top[i].x1 + 32
end
end
function add_bg_spr_to_end(tbl, w)
local x1 = tbl[#tbl - 1].x2
add(tbl, { x1 = x1, w = w, x2 = x1 + w })
end
function should_add_bg_spr(x)
-- 148 for a smoother addition since it's out of view
return x <= 148
end
function del_first_value(tbl)
del(tbl, tbl[1])
end
function is_offscreen_left(x)
return x <= 0
end
function set_new_x2(tbl, idx)
tbl[idx].x2 = tbl[idx].x1 + tbl[idx].w
end
같은 30fps 속도로 운행하는 _draw()
함수에서 나는 모든 시계를 다시 한 번 훑어보고 모든 시계 요소의 x1
값으로 모든 정령을 그렸다.중간에 한 줄이 정적이어서 책상이 없어서 그것을 놓지 않았다.나는 8회(0-7회)만 순환하면 스크린에 프레임당 8개의 정적 정령을 채울 수 있다.토지는 말단이 있기 때문에, 이곳의 처리 방식도 다르다.내가 랜드테이블을 반복할 때, 만약 인덱스가 1 (Lua 인덱스는 0이 아니라 1로 시작) 이거나, 인덱스가 그룹의 길이에 해당한다면, 나는 정령을 끝으로 설정할 것이다.만약 이것이 내가 마지막으로 flp
true로 설정한 것이라면, 이것은 정령이 x축에서 뒤집혀야 하는지를 제어합니다.주: Pico-8에서 정령은spr(정령 번호, x, y, w, h,flip x,flip y)로 그려지는데, 그중 w는 넓은 정령의 수량이고, h는 높은 정령의 수량이다.모든 요정은 8x8이기 때문에 16x16의 그림을 그리기 위해 w=2와 h=2를 설정해야 합니다
function _draw()
cls()
-- draw top row
for i = 1, #first_row do
spr(64, first_row[i].x1, 0, 2, 2) -- first_row
end
-- draw second/third rows
for i = 1, #second_row do
spr(66, second_row[i].x1, 16, 4, 4) -- second row
spr(70, third_row[i].x1, 48, 4, 2) -- third row
end
-- draw static middle row
for i = 0, 7 do
spr(96, i * 16, 64, 2, 2)
end
-- draw land
draw_land()
-- draw bottom row
for i = 1, #bottom_row do
spr(204, bottom_row[i].x1, 112, 2, 2)
end
end
function draw_land()
for i = 1, #land_top do
local flp = false
local top_spr = 196
local bottom_spr = 200
if i == 1 or i == #land_top then
top_spr = 192
bottom_spr = 232
end
if (i == #land_top) flp = true
spr(top_spr, land_top[i].x1, 64, 4, 4, flp)
spr(bottom_spr, land_bottom[i].x1, 96, 4, 2, flp)
end
end
이 모든 것이 완벽하게 최종 결과를 창조했다.그리고 내가 수량 (128px의 너비 + 최소 32px의 추가 화면 밖을 덮을 수 있음) 을 설정하고 모든 정령이 화면을 떠날 때 x
값을 변경할 수 있을 때, 왜 테이블에서 추가하거나 삭제해야 하는지 생각했다.내가 애써 시도하기 전에, 나는 사실 이런 일을 할 필요가 없다는 것을 갑자기 깨달았다.🤦♀️ 나는 책상이 아예 필요 없다.나는 한 순환에서 모든 내용을 만들 수 있으며, 두 변수를 사용하여 줄마다 x 값을 추적할 수 있다.한 번 더 해달래요.
나는 모든 테이블과 그 부수적인 기능을 삭제하고 몇 가지 새로운 변수를 만들었다.
top_startX
, middle_startX
, bottom_startX
, land_startX
.이러한 값은 각 행의 시작 위치를 제어합니다.그것들은 0으로 초기화되어 각 프레임은 줄마다 속도를 줄이고 -128까지 마이너스로 변한다.그런 다음 0으로 재설정됩니다.그래, land_startX
빼고 내가 이따가 설명할게.현재 유일하게 해야 할 일
_update()
은 줄마다 시작하는 x값에서 속도를 줄이는 것이다._draw()
에는 하나의 순환이 있는데 이 순환에서 줄마다 그려져 육지를 뺀다.정령의 폭이 적어도 32px일 때, 나는 직접 정령을 그릴 수 있다. 왜냐하면 128px 화면의 폭을 초과한 정령을 만들 수 있기 때문이다.예를 들어 i=7이면 spr(66, i * 32 + middle_startX, 16, 4, 4)
224의 x값에 middle_startX
와 같은 값을 더하여 정령을 만든다.내가 위에서 설명한 바와 같이, 그것은 각 프레임에서 줄어들어, 요정이 왼쪽으로 굴러가는 것처럼 보일 것이다.정령이 16x16에 불과할 때 오른쪽은 덮어지지 않습니다. 정령은 다음 순환이 시작되기 전에 왼쪽으로 이동하기 때문입니다.나는 최소한 16 (7이 아니라) 까지 순환해야만 완전히 덮어쓸 수 있기 때문에, x 값 + 128 (화면 너비) 에 추가 정령을 그렸다.토지에 대해 나는
land_endX
변수를 만들어야 한다. 이 변수는 토지의 길이 +1 곱하기 32(토지 부분의 너비)와 같다.그리고 리셋land_startX
을 한 번<= -land_endX
했습니다.나는 그것을 128로 리셋하지 않고 필요할 때 토지 사이의 거리를 바꾸기 위해 gap_start
파라미터를 추가했다.다음은 스크롤 효과를 만드는 전체 코드입니다.이전에 시계를 사용한 방법과 비교하면, 그것은 더욱 간단하고, 더욱 깨끗하며, 작업 원리도 같다.
function _init()
top_bg_speed = 5
bottom_bg_speed = 6
middle_bg_speed = 1
land_speed = 5
top_startX = 0
middle_startX = 0
bottom_startX = 0
land_startX = 0
end
function _draw()
cls()
palt(0, false) -- make black visible
palt(1, true) -- make darkblue transparent
-- draw bg (minus land)
for i = 0, 7 do
-- top row 16x16
spr(64, i * 16 + top_startX, 0, 2, 2)
spr(64, i * 16 + top_startX + 128, 0, 2, 2)
-- second row 32x32
spr(66, i * 32 + middle_startX, 16, 4, 4)
-- third row 32x16
spr(70, i * 32 + middle_startX, 48, 4, 2)
-- static middle row
spr(96, i * 16, 64, 2, 2)
-- bottom row 16x16
spr(204, i * 16 + bottom_startX, 112, 2, 2)
spr(204, i * 16 + bottom_startX + 128, 112, 2, 2)
end
-- draw land
draw_land(20, 128)
-- reset
if (x_should_reset(top_startX)) top_startX = 0
if (x_should_reset(middle_startX)) middle_startX = 0
if (x_should_reset(bottom_startX)) bottom_startX = 0
end
function x_should_reset(x)
return x <= -128
end
function _update()
top_startX -= top_bg_speed
middle_startX -= middle_bg_speed
bottom_startX -= bottom_bg_speed
land_startX -= land_speed
end
function draw_land(length, gap_start)
local land_endX = (length + 1) * 32 -- +1 for off screen padding
-- reset
-- gap_start is what px you want the next piece of land to start
if (land_startX <= -land_endX) land_startX = gap_start
for i = 1, length do
local flp = false
local top_spr = 196
local bottom_spr = 200
if (i == 1 or i == length) then -- end piece
top_spr = 192
bottom_spr = 232
end
if (i == length) flp = true -- right end piece
spr(top_spr, i * 32 + land_startX, 64, 4, 4, flp) -- top
spr(bottom_spr, i * 32 + land_startX, 96, 4, 2, flp) -- bottom
end
end
Reference
이 문제에 관하여(전장 두꺼비 만들기 스크롤 배경 효과), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/robotspacefish/battletoads-scrolling-background-31kc텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)