introdução à engenhariapsampaio/eng1000/slides/eng1000_aula_16_pseudo... · e simples. pseudo3d...

44
Aula 16 – Pseudo3D em Jogos de Corrida Introdução à Engenharia ENG1000 2018.1 Prof. Pedro Sampaio <[email protected]> 1

Upload: hoangthuan

Post on 20-Nov-2018

219 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Aula 16 – Pseudo3D em Jogos de Corrida

Introdução à EngenhariaENG1000

2018.1

Prof. Pedro Sampaio<[email protected]> 1

Page 2: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Pseudo3D vs 3D

2Forza Horizon 3

Top Gear 2

• Câmera fixa;• Sprites 2D;• Matemática simplificada;• Pipeline gráfico pequeno e simples.

Pseudo3D

• Câmera livre;• Modelos 3D;• Matemática robusta;• Pipeline gráfico extenso e complexo.

3D

Page 3: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

3D Rendering

3

Operações matemáticas armazenadas em estruturas de matrizes e vetores

Pipeline gráfico com procedimentos complexos como o de Culling

Page 4: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

3D Rendering

4

Pipeline gráfico OpenGL 4.4

Page 5: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Semelhança de Triângulos

5

Triângulos com lados proporcionais são semelhantes entre si

Page 6: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Projeção 3D -> 2D

6

Projetando um ponto do universo 3D para uma tela 2D:(x_world, y_world, z_world) -> (x_screen, y_screen)

Usando semelhança de triângulos calculamos nossa nova coordenada y (y_screen):

y_screen = y_world * dist / z_world

Podemos obter x_screen da mesma forma!

Page 7: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Pseudo3D - Transformações

7

Transformações para projeção dos pontos

Page 8: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Transformação de Escala

8

Precisamos escalar nosso ponto de acordo com a resolução e a orientação computacional de

coordenadas!

Page 9: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Field of View

9

Podemos configurar o campo de visão da nossa câmera alterando a distância entra a câmera e o plano 2D

Desnecessário para a maioria dos motores de corridas Pseudo3D!

Page 10: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Estrada - Geometria

10

Page 11: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Estrada – Estrutura de Dadosfunction buildRoad()

segments = {}

for n = 1, 500 do -- tamanho arbitrário para estrada (n segmentos)

seg = {

index = n, -- indíce do segmento na tabela

p1 = { -- ponto p1 do segmento

world = { z = (n-1) * segmentLength },

camera = { z = 1, y = 1, x = 1, w = 1, scale = 1},

screen = { z = 1, y = 1, x = 1, w = 1, scale = 1}

},

p2 = { -- ponto p2 do segmento

world = { z = n * segmentLength },

camera = { z = 1, y = 1, x = 1, w = 1, scale = 1},

screen = {z = 1, y = 1, x = 1, w = 1, scale = 1}

},

color = randomColorLightness(math.floor(n/rumbleLength)),

looped = false

}

table.insert(segments, seg)

end

11

function randomColorLightness(n)if n % 2 == 0 then

return COLORS.DARKelse

return COLORS.LIGHTend

end

Page 12: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Estrada – Estrutura de Dados

pSegment = findSegment(playerZ)["index"]

segments[pSegment + 2]["color"] = COLORS.START

segments[pSegment + 3]["color"] = COLORS.START

segments[pSegment + 4]["color"] = COLORS.START

segments[pSegment + 5]["color"] = COLORS.START

trackLength = tablelength(segments) * segmentLength

end

12

function findSegment(z)

return segments[(math.floor(z/segmentLength) % tablelength(segments)) + 1]

end

playerZ=cameraHeight*cameraDepth

Função tablelenght(t) retorna a quantidade de elementos em uma tabela “t”

Page 13: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Esquema de Cores

13

-- cores

skyblue = {135, 206, 235}

darkgray = {169, 169, 169}

greenmedium = {10, 111, 10}

whitesmoke = {245, 245, 245}

darkgreen = { 0, 100, 0}

white = {255, 255, 255}

-- esquema de coresCOLORS = {

SKY = skyblue,

LIGHT = { road = darkgray, grass = greenmedium, lane=whitesmoke },

DARK = { road = darkgray, grass = darkgreen },

START = { road = white, grass = greenmedium }

}

Page 14: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Movimentação – Updatefunction love.update(dt)

dx = dt * 5000 –- deslocamento no eixo x

if (keyLeft) then -- deslocar para esquerda

playerX = playerX - dx;

elseif (keyRight) then -- deloscar para direita

playerX = playerX + dx;

end

if (keyFaster) then -- acelerar movimento

speed = speed + 25

elseif (keySlower) then –- desacelerar movimento

speed = speed - 25

else -- desaceleração natural

if speed > 0 then -- considerando que movimento

speed = speed – 5 -- ocorre para frente e para trás

elseif speed < 0 then

speed = speed + 5

else

speed = 0

end

end14

Page 15: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Movimentação – Updatespeed = limit(speed, -10000, 10000) -– limita velocidade

playerX = limit(playerX, -10000, 10000) -- limita pos x

position = increase(position, dt * speed, trackLength)

end

15

function limit(value, minValue, maxValue)

return math.max(minValue, math.min(value, maxValue))

end

function increase(start, increment, maxValue) -- com looping

result = start + increment; -- da estrada

if (result >= maxValue) then

result = result - maxValue;

end

if (result < 0) then

result = result + maxValue;

end

return result;

end

Page 16: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Estrada – Projeção e Draw

function love.draw()

drawRoad() -- desenha a estrada

end

16

function project(p, cameraX, cameraY, cameraZ, cameraDepth, width, height, roadWidth)

local proj = {} -- coordeanadas após projeção

-- translação das coordenadas de acordo com a câmera

p.camera.x = (p.world.x or 0) - cameraX

p.camera.y = (p.world.y or 0) - cameraY

p.camera.z = (p.world.z or 0) - cameraZ

-- escala de acordo com a posição z da ponto no mundo 3D

p.screen.scale = cameraDepth/p.camera.z

-- projeção das coodernadas (x,y) e da largura da metade do segmento

proj.x = p.screen.scale * p.camera.x

proj.y = p.screen.scale * p.camera.y

proj.w = p.screen.scale * roadWidth

-- escala do plano matemático normalizado para o computacional

p.screen.x = round((width/2) + (proj.x * width/2))

p.screen.y = round((height/2) - (proj.y * height/2))

p.screen.w = round((proj.w * width/2))

endFunção de arredondamento comum

Page 17: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Estrada - Draw

17

function drawRoad()

baseSegment = findSegment(position)

-- desenha a partir do baseSegment

for n = 0, (drawDistance)-1 do

segment = segments[((baseSegment["index"] + n) % tablelength(segments)) + 1]

segment["looped"] = segment["index"] < baseSegment["index"]

-- projeta p1 na tela 2D

project(segment["p1"], playerX, cameraHeight,

position -(segment.looped and trackLength or 0), cameraDepth, width, height, roadWidth)

-- projeta p2 na tela 2D

project(segment["p2"], playerX, cameraHeight,

position - (segment.looped and trackLength or 0),

cameraDepth, width, height, roadWidth)

-- desenha segmentos com p1 e p2 já projetados

drawSegment(width, lanes, segment["p1"]["screen"]["x"],

segment["p1"]["screen"]["y"], segment["p1"]["screen"]["w"],

segment["p2"]["screen"]["x"], segment["p2"]["screen"]["y"],

segment["p2"]["screen"]["w"], segment["color"])

end

end

Valor definido para controlar a quantidade de segmentos desenhados a cada quadro

Page 18: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Estrada - Draw

18

function drawSegment (width, lanes, x1, y1, w1, x2, y2, w2, color)

-- desenha piso do cenário (grama) no segmento atual

love.graphics.setColor(color.grass)

love.graphics.rectangle("fill", 0, y2, width, y1 - y2)

-- desenha segmento da rua sobre a grama já desenhada

drawPolygon(x1-w1, y1, x1+w1, y1, x2+w2, y2, x2-w2,y2, color.road)

if (color.lane) then

l1 = w1 / (8*lanes) -- largura inferior da faixa

l2 = w2 / (8*lanes) -- largura superior da faixa

lane_w1 = w1*2/lanes –- largura inferior da pista

lane_w2 = w2*2/lanes –- largura superior da pista

lane_x1 = x1 - w1 + lane_w1 –- posição x inferior da pista

lane_x2 = x2 - w2 + lane_w2 –- posição x superior da pista

for lane = 1, lanes-1 do -- loop de desenho das faixas

drawPolygon(lane_x1 - l1/2, y1, lane_x1 + l1/2, y1, lane_x2 + l2/2, y2, lane_x2 - l2/2, y2, color.lane)

lane_x1 = lane_x1 + lane_w1 -- incrementa posição para

lane_x2 = lane_x2 + lane_w2 -- desenhar próxima faixa

end

end

end

Cor das faixas (color.lane) só está definida se o segmento possuir esquema de cor LIGHT

A variável “lanes” corresponde ao número de pistas que a estrada possuirá. A função “drawPolygon” utiliza a função love.graphics.polygon para desenhar o polígono recebido, além de alterar a cor de desenho com a cor recebida em seu último parâmetro

Page 19: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Importante - Desabilitar VSync

19

function love.load()

-- desabilitar VSync para evitar problemas relacionados

-- à performance do jogo

love.window.setMode(width, height, {vsync=false})

(...)

end

Page 20: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Exercício 11) Adicione o sprite de carro ao exemplo disponibilizado e faça a animação

de acordo com a movimentação do jogador

Resources:http://www.inf.puc-rio.br/~psampaio/eng1000/resources/Pseudo3DEx1.zip

20

Page 21: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Curvas 3D

21

Rascunho de curvas em um mundo 3D

• Mudança real na estrutura física dos segmentos;

• Requer cálculos complexos de rotação 3D;

• Raramente utilizado em Pseudo3D.

Page 22: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Curvas Pseudo3D

22

Curvas falsas em um mundo Pseudo3D

• Não há mudanças na estrutura dos segmentos, apenas na projeção;

• Cálculos simples, sem nenhuma rotação envolvida;

• Método recomendado para curvas em Pseudo3D;

Page 23: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Curvas Pseudo3D

23

Curvas falsas em um mundo Pseudo3D

• Como funciona?

- É necessário apenas modificar a linha central (p1, p2) de cada segmento durante a projeção;

- Para o efeito de curva, basta inclinar levemente a linha central de segmentos consecutivos criando um formato de curva.

p1

p2

p1

p2

Page 24: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Curvas Pseudo3D

24

Curvas falsas em um mundo Pseudo3D

• Precisamos armazenar o valor que representa a inclinação de cada segmento na nossa estrutura de segmentos;

- Valores negativos indicam curvas à esquerda- Valores positivos indicam curvas à direita- Valores mais altos indicam curvas acentuadas- Valores mais baixos indicam curvas suaves

p1

p2

p1

p2

Page 25: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Estrada – Estrutura Revisada

25

function addSegment(curve) –- adiciona um segmento da estrada

n = tablelength(segments) + 1;

seg = {

index = n, -- index é o tamanho atual da tabela (+1 -> lua)

p1 = { world = { z = (n-1) * segmentLength }, camera = {},

screen = {} },

p2 = { world = { z = n * segmentLength }, camera = {}, screen = {} } ,

color = randomColorLightness(math.floor(n/rumbleLength)),

looped = false,

curve = curve –- valor da inclinação do segmento

}

table.insert(segments, seg)

end

Page 26: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Estrada – Estrutura Revisada

26

-- adiciona uma porção de segmentos, suavizando curvas quandonecessário

function addRoad(enter, hold, leave, curve)

for n = 0, enter-1 do

-- interpola valores para suavizar entrada da curva

addSegment(interpolate(0, curve, n/enter))

end

for n = 0, hold-1 do

addSegment(curve)

end

for n = 0, leave-1 do

-- interpola valores para suavizar saída da curva

addSegment(interpolate(curve, 0, n/leave))

end

end -- interpolação - adiciona ao valor inicial uma porcentagem do que resta para o valor finalfunction interpolate(a,b,percent) return a + (b-a)*percent

end

Page 27: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Estrada – Estrutura Revisada

27

-- Parâmetros de uma parcela da estrada (conjunto de segmentos)

ROAD = {

LENGTH = { NONE = 0, SHORT = 25, MEDIUM = 40, LONG = 80 },

CURVE = { NONE = 0, EASY = 2, MEDIUM = 4, HARD = 6 }

}

-- Adiciona parcelas de estrada retas

function addStraight(size)

size = size or ROAD.LENGTH.MEDIUM

addRoad(size, size, size, 0) –- sem curva nessa parcela

End

-- Adiciona parcelas de estrada com curvas

function addCurve(size, curve)

size = size or ROAD.LENGTH.MEDIUM

curve = curve or ROAD.CURVE.MEDIUM

addRoad(size, size, size, curve) –- parcela com curva

end

Page 28: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Estrada – Estrutura Revisada

28

-- Adiciona parcelas de estradas com curvas em S

function addSCurves()

addRoad(ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, -ROAD.CURVE.EASY)

addRoad(ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.CURVE.MEDIUM)

addRoad(ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.CURVE.EASY)

addRoad(ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, -ROAD.CURVE.EASY)

addRoad(ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, -ROAD.CURVE.MEDIUM)

end

-- constrói a estrada completa adicionando as parcelas desejadas

function buildRoad()

(...)

addStraight(ROAD.LENGTH.SHORT/4) –- reta pequena

addSCurves() -- curva em S

addStraight(ROAD.LENGTH.LONG) -- reta comprida

addSCurves() -- curva em S

addCurve(ROAD.LENGTH.LONG, -ROAD.CURVE.MEDIUM) -- curva à esquerda...

addCurve(ROAD.LENGTH.LONG, ROAD.CURVE.MEDIUM) -- curva à direita...

addCurve(ROAD.LENGTH.LONG, -ROAD.CURVE.EASY) (...)

end

Page 29: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Estrada – Draw Revisado

29

function drawRoad()

baseSegment = findSegment(position)

basePercent = percentOf (position, segmentLength) –- evita transiçõesde segmentos bruscas

x = 0; -- deslocamento x em p1

dx = - (baseSegment["curve"] * basePercent) –- deslocamento x em p2 relativo ao x em p1

for n = 0, (drawDistance)-1 do

(...)

project(segment["p1"], playerX – x, (...)) -- desloca x da câmera

project(segment["p2"], playerX - x – dx, (...)) -- em p1 e em p2

-- atualiza valores de x e dx para próximo segmento

x = x + dx

dx = dx + segment["curve"]

(...)

end

end

-- retorna o percentual atingido por um valor em um totalfunction percentOf(n, total) return (n%total)/total

end

Page 30: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Exercício 21) Adicione ao exemplo disponibilizado uma força centrífuga que simule o

movimento de um veículo durante uma curva

Resources:http://www.inf.puc-rio.br/~psampaio/eng1000/resources/Pseudo3DEx2.zip

30

Page 31: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Adicionando Sprites

31

• Sprites 2D compatíveis com a visão da câmera

• Requer posicionamento e escala de acordo com a perspectiva do mundo

• Dois tipos de sprites: fixos e móveis

Page 32: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Adicionando Sprites

32

• Temos as informações necessárias para o desenho de sprites em cada ponto projetado!

• Podemos utilizar a escala, o x e y, e a largura da pista (w) ao projetarmos os sprites em um ponto de um segmento

• Passos para adicionar um sprite:• Armazenar em um segmento da pista• Atualizar o segmento atual do sprite (no caso de sprites móveis)• Desenhar o sprite de acordo com as informações contidas no segmento atual (utilizando p1’s ou p2’s)

function project(…)p.screen.scale = cameraDepth/p.camera.z

p.screen.x = (…)

p.screen.y = (…)

p.screen.w = (…)

end

Page 33: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Armazenando Sprites

33

function addSegment(…)

(…)

seg = {

(…)

sprites = {}, -- contém todos os sprites fixos de um segmento

cars = {}, -- contém todos os sprites móveis de um segmento

(…)

}

(…)

end

-- constantes relacionadas aos sprites

SPRITES = {

TREE1 = { x = 0, y = 50, w = 232, h = 153},

CAR01 = { x = 0, y = 0, w = 82, h = 46},

CAR02 = { x = 180, y = 0, w = 82, h = 46}

}

SPRITES.CARS = {SPRITES.CAR01, SPRITES.CAR02}

SPRITES.SCALE = 4.2

Page 34: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Armazenando Sprites

34

-- função que adiciona sprites fixos a um segmento n

function addSprite(n, sprite, offset)

-- offset é o deslocamento do sprite no eixo x

sprite = {source = sprite, offset = offset}

-- insere o sprite no segmento desejado

table.insert(segments[n]["sprites"], sprite)

end

-- função que popula a estrada com sprites fixos

function buildSprites()

addSprite(15, SPRITES.TREE1, -roadWidth) -- adiciona sprite TREE1 nos

addSprite(20, SPRITES.TREE1, -roadWidth) -- segmentos 15 e 20 à

-- esquerda da estrada

n = 21 -- a partir do segmento 21, adiciona sprite TREE1 à esquerda

-- e à direita da estrada, a cada rumbleLength * 2 segmentos

while n < tablelength(segments) do

addSprite(n, SPRITES.TREE1, -roadWidth)

addSprite(n, SPRITES.TREE1, roadWidth)

n = n + (rumbleLength * 2)

end

end

Page 35: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Armazenando Sprites

35

-- função que popula a estrada com sprites móveis

function buildCars()

cars = {} -- tabela auxiliar para facilitar a atualização dos sprites

-- insere sprites móveis na estrada randomicamente

for n = 0, totalCars do -- totalCars equivale a qtd de sprites móveis

-- randomiza um offset no eixo x para o sprite

-- OBS: randomChoice escolhe aleatóriamente um valor de uma tabelaoffset = math.random() * randomChoice({-0.8*roadWidth, 0.8*roadWidth})

-- randomiza posição z do sprite

z = math.floor(math.random() * tablelength(segments))*segmentLength

-- randomiza o sprite móvel a ser usado e sua velocidade

sprite = randomChoice(SPRITES.CARS)

carspeed = maxSpeed/4 + math.random() * maxSpeed

segment = findSegment(z)

car = { offset = offset, z = z, sprite = sprite, speed = carspeed, percent = 0, segment = segment}

-- insere o carro gerado na estrada e também na tabela auxiliar

table.insert(segment["cars"], car)

table.insert(cars, car)

end

end

Page 36: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Atualizando Sprites

36

-- função que atualiza posição dos sprites móveis (no ex. carros)

function updateCars(dt) -- deve ser chamado no love.update()

for n = 1, tablelength(cars) do -- percorre tabela de carros auxiliar

car = cars[n]

oldSegment = car["segment"] -- segmento pré-atualização do carro

-- atualiza posição z do carro de acordo com sua velocidade

car["z"] = increase(car["z"], dt * car["speed"], trackLength)

-- atualiza percentual percorrido do segmento atual

car["percent"] = percentOf(car["z"], segmentLength) -- facilita desenho

newSegment = findSegment(car["z"]) -- segmento pós-atualização

car["segment"] = newSegment -- atualiza segmento do carro

-- se novo segmento é diferente do antigo

-- troca o segmento do carro na estrutura da estrada

if (oldSegment ~= newSegment) then

table.remove(oldSegment["cars"], indexOf(oldSegment["cars"], car))

-- indexOf retorna indíce de um objeto em uma tabela

table.insert(newSegment["cars"], car)

end

end

end

Page 37: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Desenhando Sprites

37

-- função que desenha todos os sprites (deve ser chamada no love.draw())

function drawSprites()

-- loop em ordem contrária: algoritmo do pintor

-- desenhamos o que está atrás primeiro!

n = (drawDistance-1)

while n > 0 do

-- segmento atual do loop

segment = segments[((baseSegment["index"] + n) % tablelength(segments)) + 1]

(… desenha sprites fixos …)

(… desenha sprites móveis …)

(… desenha sprite do player …)

-- decrementa iterador do loop: algoritmo do pintor

n = n - 1

end

end

Page 38: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Desenhando Sprites

38

(… desenha sprites fixos …)

for i = 1 , tablelength(segment["sprites"]) do

sprite = segment["sprites"][i]

spriteScale = segment["p1"]["screen"]["scale"]

spriteX = segment["p1"]["screen"]["x"] +

(spriteScale * sprite["offset"] * width/2)

spriteY = segment["p1"]["screen"]["y"]

drawSprite(width, height, resolution, roadWidth, sprites, sprite["source"], spriteScale, spriteX, spriteY, (sprite["offset"] < 0 and -1 or 0), -1)

end

Page 39: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Desenhando Sprites

39

(… desenha sprites móveis …)

for i = 1 , tablelength(segment["cars"]) do

car = segment["cars"][i]

sprite = car["sprite"]

spriteScale = interpolate(segment["p1"]["screen"]["scale"], segment["p2"]["screen"]["scale"], car["percent"])

spriteX = interpolate(segment["p1"]["screen"]["x"], segment["p2"]["screen"]["x"], car["percent"]) + (spriteScale * car["offset"] * width/2)

spriteY = interpolate(segment["p1"]["screen"]["y"], segment["p2"]["screen"]["y"], car["percent"])

drawSprite(width, height, resolution, roadWidth, sprites, car["sprite"], spriteScale, spriteX, spriteY, -0.5, -1)

end

Page 40: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Desenhando Sprites

40

(… desenha sprite do player …)

if (segment == playerSegment) then

drawSprite(width, height, resolution, roadWidth, sprites, SPRITES.CAR02,

cameraDepth/playerZ,

width/2,

(height/2),

-0.5,

1);

end

-- atualizado dentro do love.update()playerSegment = findSegment(position+playerZ) -- position + playerZ eqvuiale à:-- posição da câmera + distância(fixa) do player para câmera

Page 41: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Desenhando Sprites

41

-- função que desenha sprites aplicando escalas e offsets

-- de acordo com parâmetros passados

function drawSprite(width, height, resolution, roadWidth, sprites, sprite, scale, destX, destY, offsetX, offsetY)

destW = (sprite.w * scale * width) * SPRITES.SCALE

destH = (sprite.h * scale * width) * SPRITES.SCALE

destX = destX + (destW * offsetX)

destY = destY + (destH * offsetY)

quad = love.graphics.newQuad(sprite.x, sprite.y, sprite.w, sprite.h, sprites:getDimensions())

love.graphics.draw(sprites, quad, destX, destY, 0, (destW)/sprite.w, (destH )/sprite.h)

end

Page 42: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Collision Check

42

n segmentos

• Basta checar um número de segmentos no entorno do segmento atual do player

• Se em algum dos segmentos checados houver sprites, precisamos apenas verificar se houve colisão no eixo x

• Para colisão com sprites fixos, checar o segmento atual do player já é o suficiente

Page 43: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Exercícios1) Implemente a detecção de colisões entre o player e os sprites (fixos e

móveis) da estrada. Utilize o exemplo disponibilizado como base.OBS: o exemplo disponibilizado possui uma função pronta para checarcolisão no eixo x (function overlap) que recebe o x e o width de dois sprites e retorna “true” caso haja colisão. Lembre-se que o width é multiplicado pelo SPRITES.SCALE

Resources:http://www.inf.puc-rio.br/~psampaio/eng1000/resources/Pseudo3DEx3.zip

43

Page 44: Introdução à Engenhariapsampaio/eng1000/slides/ENG1000_Aula_16_Pseudo... · e simples. Pseudo3D ... -- interpola valores para suavizar saída da curva. ... -- Adiciona parcelas

Leitura Complementar

• Lou's Pseudo 3d Page– http://www.inf.puc-rio.br/~psampaio/eng1000/resources/LouPseudo3D.pdf

44