• Nenhum resultado encontrado

3.5 Modelo representativo

4.1.2 Estrutura e funcionalidades

Nesta seção, a estrutura interna do jogo será abordada a fim de destacar o impacto que o método proposto neste trabalho causou na implementação desta prova de conceito. Assim, as principais funcionalidades do jogo serão descritas como forma de evidenciar a simplicidade da utilização do referido método ante as vantagens oferecidas por ele.

Durante a inicialização do jogo, um objeto contendo os três modelos geométricos é criado, código 4.2. Nele, cada espaço geométrico é definido por nome, curvatura, shader e função de atualização. Posteriormente, o espaço geométrico no qual o jogo será iniciali- zado é definido, além da instanciação de outros objetos utilizados no jogo, e.g., a nave ou a lista de asteroides da primeira wave. Por fim, os tratadores de eventos são inicializados e dá-se início ao loop principal do jogo.

1 Asteroides podem ter valores de hp distintos, sendo necessário quantidades diferentes de tiros para

4.1 EXPERIMENTO PRÁTICO - ASTEROIDS 45 Código 4.2: Geometrias 1 @geometries = 2 euclidean: 3 name: "euclidean" 4 k: 0

5 shader: cofgl.resmgr.resources[’shaders/euclidean’] 6 step: cofgl.euclidTorusStep

7 elliptic:

8 name: "elliptic"

9 k: 1

10 shader: cofgl.resmgr.resources[’shaders/elliptic’] 11 step: cofgl.kleinStep

12 hyperbolic:

13 name: "hyperbolic"

14 k: -1

15 shader: cofgl.resmgr.resources[’shaders/hyperbolic’] 16 step: cofgl.poincareBitorusStep

17 @geometry = @geometries.euclidean

De forma simplificada, a função mainloop se encarrega de aspectos fundamentais: • Atualização do contexto do jogo, onde todo o funcionamento interno e controle das

mecânicas ocorre, e.g., controle de colisões e I/O. • Renderização do frame.

• Atualização dos dados e renderização da UI (user interface). • Composição da cena com a UI.

Dentre as ações feitas durante a atualização do jogo, destaca-se o teste de colisões, código A.5. Nele, a geometria em uso, apresentada no código 4.2, é utilizada para obter a curvatura do espaço em uso. De posse da curvatura k, é possível empregar a equação (.) para determinar a distância real entre dois objetos, independentemente do espaço geo- métrico em uso no jogo, código A.5. Assim, usando o raio dos objetos analisados em conjunto com a distância recém obtida, se estabelece uma forma rudimentar de detecção de colisão, mas suficiente para as necessidades do jogo em questão. Para casos que uma detecção mais detalhada se faça necessária, a mesma função de cálculo de distância utili- zada neste exemplo pode ser empregada no desenvolvimento de sistemas de colisões mais minuciosos.

Os testes de colisões são feitos primeiramente entre os asteroides e os tiros disparados. Se houver colisão, o tiro danifica o asteroide e se extingue - a nave pontua de acordo com o dano causado no asteroide. Uma vez que o hp do asteroide seja zerado, ele é destruído. O segundo conjunto de testes é feito entre os asteroides e a nave. Neste caso de colisão, a nave perde um ponto de vida e é reposicionada no centro da tela ou é considerado um game over e o jogo é reiniciado, conforme a seção 4.1. Ainda, o controle dos inputs do jogador são feitos também durante a atualização contextual do jogo, assim como a atualização de cada objeto individual. A atualização de cada objeto consiste do processo descrito na seção 3.5, através dos códigos 3.1, 3.2 e 3.4.

46 METODOLOGIA A renderização faz uso dos shaders descritos na seção 3.5.1. Além destes, o plano de fundo utilizado nos três espaços geométricos é feito por um shader a parte, detalhes disponíveis na seção A.3.

A GUI (graphical/game user interface) foi feita de uma forma simples e direta, através de uma composição de canvas. O elemento canvas é capaz de trabalhar com imagens, da criação ao processamento, porém um interessante uso seu é utilizar um outro canvas como imagem de entrada. Desta forma, são utilizados três canvas distintos: (i) “viewport” com contexto WebGL, no qual o jogo é renderizado (figura 4.1 (a)); (ii) “gui” com contexto ‘2d’, exibindo todos os dados referentes a GUI(figura 4.1 (b)); e, (iii) “composite” com o contexto ‘2d’, para fazer a composição dos dois canvas anteriores. Na composição, a propriedade globalCompositeOperation do “composite” é definida como “source-over”, desta forma, os dados referentes a GUI sobrepõem o jogo, gerando a renderização final: figura 4.1 (c).

(a) Renderização da GUI em

um canvas com contexto 2d. (b) Renderização do jogo emum segundo canvas, com con- texto WebGL.

(c) Composição gerando a ren- derização final.

Figura 4.1: Composição da GUI.

O apêndice A, seção A.2, traz o código responsável pela estrutura do jogo discutida ao longo desta seção, código A.5. A versão final do jogo está disponível em [Non-Euclidean Spaceship 2015].

Capítulo

5

Este capítulo traz as conclusões desta dissertação. Nele, serão apresentadas as considerações finais junto com a discussão acerca das contribuições geradas por este trabalho. Além disso, serão abordados os possíveis trabalhos futuros.

CONCLUSÕES

A frase introdutória do capítulo 1 destaca a presença da geometria euclidiana na nossa sociedade. Essa influência vai além do impacto na forma como nós identificamos o espaço no qual estamos inseridos. Ela permeia nosso subconsciente de maneira que, ao pen- sar em questões geométricas, o arquétipo euclidiano é utilizado como se fosse absoluto, desconsiderando outros modelos geométricos.

Ao considerar a ignorância relativa às geometrias não euclidianas por parte de uma grande parcela da população, de acordo com o discutido na seção 1.1, fica evidente que a apresentação destas geometrias não é realizada de maneira satisfatória. É comum que a introdução destas geometrias seja feita de forma abstrata e teórica, gerando conflitos entre conceitos já familiares aos estudantes. A ideia de uma linha reta - na geometria euclidiana - é apresentada como uma curva nas geometrias não euclidianas exploradas neste trabalho. Este exemplo simples ilustra bem os desafios que estão associados à quebra de paradigma que é o ensino de geometrias não euclidianas.

A complexidade da compreensão dos conceitos não euclidianos está intimamente ligada à dificuldade de visualização desses conceitos, representando uma das principais barreiras no aprendizado dessas geometrias. Nesse cenário, a utilização de alguma forma de auxílio no desenvolvimento de jogos não euclidianos se torna promissora.

Como uma proposta de abstrair a complexidade inerente às geometrias não euclidia- nas, este trabalho propôs a definição de um modelo de encapsulamento para o desenvolvi- mento de jogos 2D em três espaços geométricos distintos (a saber: o euclidiano, o elíptico e o hiperbólico). Deste modo, uma implementação que faça uso do modelo de encapsu- lamento proposto não precisa lidar diretamente com as particularidades de nenhuma das geometrias, embora possa ser executada em qualquer uma delas. Assim, o processo de desenvolvimento para jogos não euclidianos pode ser simplificado, abstraindo a comple- xidade relacionada às geometrias não euclidianas, e se torna trivial a representação de um jogo em diferentes modelos geométricos.

48 CONCLUSÕES

5.1 CONSIDERAÇÕES FINAIS

Neste trabalho foi introduzido um modelo de encapsulamento geometricamente genérico, capaz de representar um universo (game universe) em múltiplas geometrias. Desta forma, foi viabilizado um método prático de contraste entre espaços geométricos, sendo possível utilizá-lo com fins pedagógicos ou simplesmente como forma de simplificar a implemen- tação de aplicações que façam uso de geometrias não euclidianas.

A validação prática deste modelo de encapsulação se deu através da implementação do clássico de arcade: Asteroids, figura 5.1. Assim, foi possível comparar a represen- tação e o comportamento deste conhecido jogo em três espaços geométricos distintos, a saber, o euclidiano, o elíptico e o hiperbólico. Para pessoas familiarizadas com o jogo, a aplicação serve como uma demonstração prática das diferenças implícitas nesses modelos geométricos e se torna um exercício mental singular. No entanto, a escolha desse jogo, em específico, se deu também devido a sua simplicidade. Seus controles acessíveis e objetivos intuitivos o tornam um ótimo jogo de apresentação para pessoas não habituadas a jogos em geral. A utilização de um jogo na apresentação de geometrias não euclidianas visa simplificar o estudo dessas geometrias, incentivando a compreensão de seus conceitos par- ticulares e incentivando o jogador a superar os desafios gerados por cada representação geométrica.

(a) Representação no espaço

euclidiano. (b) Representação no espaçoelíptico. (c) Representação no espaço hi-perbólico. Figura 5.1: Implementação do jogo Asteroids.

5.1.1 Publicações

Atualmente, é comum que novas pesquisas, ideias ou propostas sejam avaliadas pela própria comunidade científica. Essa avaliação, teste ou mesmo revisão, feita por terceiros, é uma forma natural de difusão de novos conhecimentos, além de ser de suma importância para o avanço científico. À vista disso, um artigo contendo o modelo de encapsulamento proposto neste trabalho foi publicado: [Guimarães, Mello e Velho 2015]. A publicação se deu no SIBGRAPI 2015 (XXVIII Conference on Graphics, Patterns and Images), no âmbito do Workshop of Works in Progress.

5.2 CONTRIBUIÇÕES 49

5.2 CONTRIBUIÇÕES

Como forma de propiciar a introdução de geometrias não euclidianas para um público maior, este trabalho apresentou um método de encapsulação de atributos com depen- dência geométrica, tornando possível um desenvolvimento que independe da geometria final na qual o conteúdo será apresentado. Para se chegar ao encapsulamento geome- tricamente independente, este trabalho propôs ainda uma forma original de considerar o espaço geométrico de um universo de jogo e de suas características internas. A en- capsulação proposta tem o potencial de impactar o modo como “jogos não euclidianos” são implementados ao simplificar este processo, graças à abstração dos conceitos relaci- onados às geometrias não euclidianas. Finalmente, como prova de conceito do método proposto, um jogo clássico (Asteroids) foi implementado e está disponível para acesso livre em [Non-Euclidean Spaceship 2015].

5.3 TRABALHOS FUTUROS

O trabalho aqui apresentado aborda espaços geométricos euclidianos e não euclidianos com uma limitação dimensional, se atendo ao 2D. Desta forma, é natural que a con- tinuidade deste trabalho expanda a abordagem inicial para três dimensões. Inclusive, seria interessante aprofundar o estudo incluindo também variedades de dimensão 3, sem- pre mantendo o conceito inicial de independência geométrica, para viabilizar a transição entre diferentes espaços. Esta abordagem seria interessante, ainda, do ponto de vista cos- mológico, viabilizando tanto representações de modelos cosmológicos distintos quanto a utilização em sistemas interativos, e.g., jogos, simulações etc. Também, analogamente às suas contribuições, este trabalho poderia ser utilizado com fins educacionais em diversos campos, apresentando as particularidades e as diferentes formas de visualizar o espaço.

Apêndice

A

Este apêndice traz o conjunto de classes centrais utilizadas na implementação de Asteroids discutida neste trabalho. Ainda, é apresentado o shader responsável por criar o campo estelar empregado como plano de fundo na implementação do jogo.

IMPLEMENTAÇÕES

O capítulo 4 descreve a implementação da prova de conceito realizada para demonstrar as aplicações práticas do modelo de encapsulamento desenvolvido neste trabalho. Como complemento, este apêndice apresenta os códigos relacionados às classes mencionadas nas seções 4.1.1 e 4.1.2.

A.1 OBJETOS

Código A.1: Classe SpaceShip 1 step_iterations = 5

2 max_vel = 5

3

4 class SpaceShip 5 constructor: ->

6 @texture = cofgl.Texture.fromImage cofgl.resmgr.resources[’space/spaceship’], {

7 mipmaps: true, 8 filtering: ’LINEAR’ 9 } 10 @inv = 1.0 11 @q = new cofgl.Complex(0.0,0.0) 12 @p = new cofgl.Complex(0.0,0.0) 13 @dir = new cofgl.Complex(1.0,0.0) 14 ang = Math.PI/180 * 5

15 @left = new cofgl.Complex(Math.cos(ang),Math.sin(ang)) 16 @right = new cofgl.Complex(Math.cos(-ang),Math.sin(-ang)) 17 @ts = 13.0 18 @radius = 2/@ts 19 @mass = 10 20 @hp = 3 21 @score = 0 22 @wave = 0 23 @hit = false 24 @lastBulletTime = 0 25 @bulletsUsed = 0 26 @bulletCooldown = 100 27 @dec = 0.98 51

52 IMPLEMENTAÇÕES 28 @cSides = [10.0, 10.0]

29

30 update: (dt) ->

31 for i in [1 .. step_iterations]

32 [@q, @p, @dir, @inv, @cSides] = cofgl.game.geometry.step(@q, @p, @dir, dt/step_iterations, @inv, @cSides) 33 @dir = @dir.plus @p

34 @dir.normalize() 35 #desaceleração 36 @p.x = @p.x * @dec 37 @p.y = @p.y * @dec 38

39 rotateLeft: ->

40 @p = @p.times @left 41 @dir = @dir.times @left 42

43 rotateRight: ->

44 @p = @p.times @right 45 @dir = @dir.times @right 46

47 thurst: ->

48 v = new cofgl.Complex(@dir.x/10.0, @dir.y/10.0) 49 @p = @p.plus (v)

50 if @p.y > max_vel then @p.y = max_vel 51 if @p.x > max_vel then @p.x = max_vel 52 if @p.y < -max_vel then @p.y = -max_vel 53 if @p.x < -max_vel then @p.x = -max_vel 54

55 break: ->

56 v = new cofgl.Complex(-(@dir.x)/10.0, -(@dir.y)/10.0) 57 @p = @p.plus (v) 58 59 hitShield: -> 60 self = this 61 @q = new cofgl.Complex(0.0,0.0) 62 @p = new cofgl.Complex(0.0,0.0) 63 setTimeout(-> 64 self.hit = false 65 ,1500) 66 67 root = self.cofgl ?= {} 68 root.SpaceShip = SpaceShip

Código A.2: Classe Bullet 1 step_iterations = 5

2

3 class Bullet

4 constructor: (spq, spp, spd)->

5 @texture = cofgl.Texture.fromImage cofgl.resmgr.resources[’space/laser’], {

6 mipmaps: true,

7 filtering: ’LINEAR’

8 }

9 @inv = 1.0

10 acceleration = switch cofgl.game.geometry.name 11 when "euclidean" then 4.0

12 when "elliptic" then 15.0

13 when "hyperbolic" then 20.0

14 @q = new cofgl.Complex(spq.x, spq.y) 15 @p = new cofgl.Complex(0.0, 0.0) 16 @dir = new cofgl.Complex(spd.x, spd.y)

17 v = new cofgl.Complex(@dir.x*acceleration, @dir.y*acceleration) 18 @p = @p.plus (v)

19 @width = 0.01

A.1 OBJETOS 53 21 @ts = 13.0 22 @radius = 2/@ts 23 @mass = 0.1 24 @faded = false 25 self = this 26 setTimeout(-> 27 self.faded = true 28 ,800) 29 @cSides = [10.0, 10.0] 30 31 update: (dt) -> 32 for i in [1 .. step_iterations]

33 [@q, @p, @dir, @inv, @cSides] = cofgl.game.geometry.step(@q, @p, @dir, dt/step_iterations, @inv, @cSides) 34 @dir = @dir.plus @p

35 @dir.normalize() 36

37 root = self.cofgl ?= {} 38 root.Bullet =Bullet

Código A.3: Classe Asteroid 1 step_iterations = 5

2

3 class Asteroid

4 constructor: (q, p, @initial)->

5 @texture = cofgl.Texture.fromImage cofgl.resmgr.resources[’space/’+ (if @initial then ’asteroid1’

6 else ’asteroid’)], {

7 mipmaps: true,

8 filtering: ’LINEAR’

9 }

10 @inv = 1.0

11 @q = new cofgl.Complex(q.x, q.y) 12 @p = new cofgl.Complex(p.x, p.y) 13 @dir = new cofgl.Complex(1.0,0.0) 14 ang = Math.PI/180 * 5

15 @left = new cofgl.Complex(Math.cos(ang),Math.sin(ang)) 16 @right = new cofgl.Complex(Math.cos(-ang),Math.sin(-ang)) 17 if @initial 18 @ts = 9.0 19 @radius = 2/@ts 20 @mass = 50 21 @hp = 3 22 else 23 @ts = 15.0 24 @radius = 2/@ts 25 @mass = 20 26 @hp = 2 27 @cSides = [10.0, 10.0] 28 29 update: (dt) -> 30 for i in [1 .. step_iterations]

31 [@q, @p, @dir, @inv, @cSides] = cofgl.game.geometry.step(@q, @p, @dir, dt/step_iterations, @inv, @cSides) 32 @dir = @dir.plus @p

33 @dir.normalize() 34

35 root = self.cofgl ?= {} 36 root.Asteroid = Asteroid

Código A.4: Classe World 1 class World

54 IMPLEMENTAÇÕES 3 @shader = cofgl.game.geometry.shader

4 @bgColor = cofgl.floatColorFromHex ’#F2F3DC’

5 @vbo = cofgl.makeQuadVBO() 6 @spaceShip.world = this 7 now = new Date()

8 @startTime = now.getTime() 9 for @asteroid in @asteroids 10 @asteroid.world = this 11 for @bullet in @bullets 12 @bullet.world = this

13 @backgroundShader = cofgl.resmgr.resources[’shaders/starfield’] 14 15 update: (dt) -> 16 17 draw: -> 18 cofgl.clear ’#fff’ 19 20 #starField

21 now = new Date()

22 time = now.getTime() - @startTime

23 cofgl.withContext [@backgroundShader], =>

24 @backgroundShader.uniform1f "time", time/1000

25 @backgroundShader.uniform2f "resolution", cofgl.engine.width, cofgl.engine.height 26 @vbo.draw()

27

28 #Asteroids

29 for @asteroid in @asteroids 30 q = @asteroid.q 31 p = @asteroid.p 32 dir = @asteroid.dir 33 ts = @asteroid.ts 34 inverted = @asteroid.inv 35 cSides = @asteroid.cSides

36 cofgl.withContext [@shader, @asteroid.texture], =>

37 @shader.uniform2f "uq", q.x, q.y 38 @shader.uniform2f "up", p.x, p.y 39 @shader.uniform2f "udir", dir.x, dir.y 40 @shader.uniform1f "texSize", ts 41 @shader.uniform1f "inverted", inverted 42 @shader.uniform1f "glueSide1", cSides[1] 43 @shader.uniform2f "glueSide2", cSides[0]

44 @vbo.draw()

45

46 #Bullets

47 for @bullet in @bullets 48 q = @bullet.q 49 p = @bullet.p 50 dir = @bullet.dir 51 ts = @bullet.ts 52 inverted = @bullet.inv 53 cSides = @bullet.cSides

54 cofgl.withContext [@shader, @bullet.texture], =>

55 @shader.uniform2f "uq", q.x, q.y 56 @shader.uniform2f "up", p.x, p.y 57 @shader.uniform2f "udir", dir.x, dir.y 58 @shader.uniform1f "texSize", ts 59 @shader.uniform1f "inverted", inverted 60 @shader.uniform1f "glueSide1", cSides[1] 61 @shader.uniform2f "glueSide2", cSides[0]

62 @vbo.draw() 63 64 #SpaceShip 65 q = @spaceShip.q 66 p = @spaceShip.p 67 dir = @spaceShip.dir 68 ts = @spaceShip.ts

A.2 ESTRUTURA INTERNA 55

Documentos relacionados