<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Abrindo o Jogo &#187; Programação</title>
	<atom:link href="http://www.abrindoojogo.com.br/category/programacao/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.abrindoojogo.com.br</link>
	<description>Abrindo o Jogo</description>
	<lastBuildDate>Thu, 29 Jul 2010 01:40:22 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Anti-Invaders &#8211; um projeto didático.</title>
		<link>http://www.abrindoojogo.com.br/2010/06/30/anti-invaders-um-projeto-didatico/</link>
		<comments>http://www.abrindoojogo.com.br/2010/06/30/anti-invaders-um-projeto-didatico/#comments</comments>
		<pubDate>Wed, 30 Jun 2010 00:54:10 +0000</pubDate>
		<dc:creator>Luiz Alessandro Nörnberg</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Padrão de Projeto]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Projeto de Jogo]]></category>
		<category><![CDATA[Projeto de Software]]></category>
		<category><![CDATA[Técnico]]></category>

		<guid isPermaLink="false">http://blog.abrindoojogo.com.br/?p=1565</guid>
		<description><![CDATA[Este post é o primeiro de uma série que vai documentar a evolução de um projeto inteiro, desde o game design até o produto final. O projeto tem o objetivo de ser didático e por isso foi escolhido um jogo de navinha (shooter) e será desenvolvido utilizando a tecnologia Java. Neste post conheceremos a primeira [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.abrindoojogo.com.br/wp-content/uploads/2010/06/blog2.png"><img class="alignleft size-full wp-image-1580" title="blog2" src="http://www.abrindoojogo.com.br/wp-content/uploads/2010/06/blog2.png" alt="" width="150" height="150" /></a>Este post é o primeiro de uma série que vai documentar a evolução de um projeto inteiro, desde o game design até o produto final. O projeto tem o objetivo de ser didático e por isso foi escolhido um jogo de navinha (shooter) e será desenvolvido utilizando a tecnologia Java. Neste post conheceremos a primeira versão do GDD e a história de fundo do jogo.</p>
<p><span id="more-1576"></span>O nome do jogo é <strong>Anti-Invaders</strong>. É um jogo de tiro espacial como vários outros que apareceram ao longo do tempo. É um gênero bem conhecido e de implementação relativamente simples, por isso mesmo uma boa escolha para um projeto didático.</p>
<p>A idéia é mostrar umprojeto simples porém completo, desenvolvido com protótipos e releases e comentando cada evolução em posts semanais. Serão decisões de game design, de arquitetura de software e de implementação que, no final, darão uma visão completa do processo.</p>
<p>Acredito que será útil principalmente para quem está iniciando e não tem, ainda, noção clara do processo como um todo.</p>
<p>Iniciaremos, então, com a primeira versão do GDD (Game Design Document), criado com base <a href="http://blog.abrindoojogo.com.br/2009/09/03/trabalhar-com-jogos-e-uma-questao-de-sorte-parte-1-de-3/">neste post do Everton</a>, embora bem simplificado. Algumas seções não foram preenchidas &#8211; nelas está anotado o que deveria ser colocado alí. O foco deste documento é na história de base, fases (tamanho do jogo) e controles. Clique no link abaixo para baixar o PDF.</p>
<p><a href="http://www.abrindoojogo.com.br/wp-content/uploads/2010/06/gdd_anti_invaders.pdf">GDD_Anti_Invaders</a></p>
<p>Semana que vem teremos um protótipo do jogo para ter idéia do que querermos fazer.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.abrindoojogo.com.br/2010/06/30/anti-invaders-um-projeto-didatico/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Threads, apenas um exemplo</title>
		<link>http://www.abrindoojogo.com.br/2009/10/08/threads-apenas-um-exemplo/</link>
		<comments>http://www.abrindoojogo.com.br/2009/10/08/threads-apenas-um-exemplo/#comments</comments>
		<pubDate>Thu, 08 Oct 2009 01:43:30 +0000</pubDate>
		<dc:creator>Luiz Alessandro Nörnberg</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Técnico]]></category>

		<guid isPermaLink="false">http://blog.abrindoojogo.com.br/?p=862</guid>
		<description><![CDATA[Threads são partes de um programa que executam paralelamente. Com seu uso é possível executar simultâneamente duas ou mais rotinas. Atualmente, com o barateamento dos processadores de vários núcleos (multi core), seu uso fica mais justificado. Embora eu não recomende trabalhar com threads, convém entender o que elas representam na prática.
Antes de tudo vou ressaltar: [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/threads.png"><img class="alignleft size-full wp-image-875" title="Threads" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/threads.png" alt="Threads" width="200" height="150" /></a><em>Threads</em> são partes de um programa que executam paralelamente. Com seu uso é possível executar simultâneamente duas ou mais rotinas. Atualmente, com o barateamento dos processadores de vários núcleos (<em>multi core</em>), seu uso fica mais justificado. Embora eu não recomende trabalhar com <em>threads</em>, convém entender o que elas representam na prática.</p>
<p><span id="more-862"></span>Antes de tudo vou ressaltar: não recomendo trabalhar com <em>threads</em> a menos que seja o desenvolvimento de um jogo AAA, o qual não é foco deste site (digamos um Batman: Asilo Arkhan). Jogos assim, exigem intenso processamento de I.A., física e gráficos e possuem, em geral, muito dinheiro para serem feito. Isso justifica a utilização de uma forma de programação mais complexa. Ainda mais que estes jogos em geral são criados em C++, uma das piores linguagens para trabalhar com <em>threads</em>. Mesmo no Java, cujo uso é relativamente simples (como veremos abaixo), depurar um programa com <em>thread</em> é um inferno.</p>
<p>Além disso, projetar o código para tirar proveito de <em>threads</em> é tarefa para arquitetos competentes &#8211; caso contrário você vai criar um código complexo, difícil de depurar e manter e, provavelmente, vai cair em <em>dead locks</em> e outros problemas de concorrência . E ainda corre o risco de acabar com um código pouco eficiente, apesar do esforço adicional.</p>
<p>Fica então o aviso: o código abaixo serve para efeito de exemplo e não deve ser base para um jogo do mundo real.</p>
<p>Bom, se depois do que foi dito acima você ainda não desistiu de ler sobre <em>threads</em>, vamos em frente &#8211; o fato é que o conceito por trás delas, e sua correta utilização, são importantes para tirar todo proveito de uma CPU com múltiplos núcleos. Vamos ver como fazer isso com o <em>gameloop</em> desenvolvidos nos meus artigos anteriores. Se você não leu, filtre os posts pela tag <strong>Java </strong>e leia-os antes, ok?</p>
<h2>Modularizando o jogo</h2>
<p>Começo criando duas classes especializadas em atualizar a lógica do jogo (lembra do <em>update</em>?) e em atualizar a tela (lembra do <em>render</em>?). Chamarei elas de Controlador e Renderizador, respectivamente. Seu código está abaixo. Basicamente, eu tirei as rotinas update() e render() da minha classe do jogo e coloquei em classes separadas.</p>
<p><strong>Arquivo Controlador.java</strong></p>
<pre style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">package</span> abrindoojogo.exemplos.thread;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span></span><span style="color:#0000e6;">import</span> javax.swing.JFrame;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">005</span></span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">class</span> Controlador<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">006</span></span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span>    </span>Contador contador;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span>    </span>JFrame frame;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">009</span>    </span>Nave nave;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">011</span>    </span><span style="color:#0000e6;">public</span> Controlador(JFrame frame, Contador contador, Nave nave)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">012</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">013</span>        </span><span style="color:#0000e6;">this</span>.frame = frame;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">014</span>        </span><span style="color:#0000e6;">this</span>.contador = contador;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">015</span>        </span><span style="color:#0000e6;">this</span>.nave = nave;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">016</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">017</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">018</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> update()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">019</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">020</span>        </span>contador.contaPulso();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">021</span>        </span>nave.x += <span style="color:#000000;">1</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">022</span>        </span><span style="color:#0000e6;">if</span> (nave.x &gt; frame.getWidth() + <span style="color:#000000;">30</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">023</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">024</span>            </span>nave.x = <span style="color:#000000;">0</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">025</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">026</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">027</span></span>}</pre>
<p><strong>Arquivo Renderizador.java</strong></p>
<pre style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">package</span> abrindoojogo.exemplos.thread;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span></span><span style="color:#0000e6;">import</span> java.awt.Color;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span></span><span style="color:#0000e6;">import</span> java.awt.Graphics2D;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">005</span></span><span style="color:#0000e6;">import</span> java.awt.image.BufferStrategy;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">006</span></span><span style="color:#0000e6;">import</span> javax.swing.JFrame;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span></span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">class</span> Renderizador<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">009</span></span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span>    </span>BufferStrategy bs;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">011</span>    </span>Contador contador;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">012</span>    </span>JFrame frame;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">013</span>    </span>Nave nave;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">014</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">boolean</span> terminado = <span style="color:#0000e6;">false</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">015</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">016</span>    </span><span style="color:#0000e6;">public</span> Renderizador(JFrame frame, BufferStrategy bs,<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">017</span>                        </span>Contador contador, Nave nave)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">018</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">019</span>        </span><span style="color:#0000e6;">this</span>.frame = frame;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">020</span>        </span><span style="color:#0000e6;">this</span>.bs = bs;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">021</span>        </span><span style="color:#0000e6;">this</span>.contador = contador;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">022</span>        </span><span style="color:#0000e6;">this</span>.nave = nave;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">023</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">024</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">025</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> render()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">026</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">027</span>        </span>contador.contaFrame();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">028</span>        </span>Graphics2D g = (Graphics2D) bs.getDrawGraphics();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">029</span>        </span>g.setColor(Color.black);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">030</span>        </span>g.fillRect(<span style="color:#000000;">0</span>, <span style="color:#000000;">0</span>, frame.getWidth(), frame.getHeight());<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">031</span>        </span><span style="color:#0000e6;">int</span> x = nave.x;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">032</span>        </span><span style="color:#0000e6;">int</span> y = nave.y;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">033</span>        </span><span style="color:#0000e6;">for</span> (<span style="color:#0000e6;">int</span> i = <span style="color:#000000;">0</span>; i &lt; nave.qtd; i++)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">034</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">035</span>            </span>g.setColor(Color.yellow);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">036</span>            </span>g.drawLine(x, y, x - <span style="color:#000000;">20</span>, y - <span style="color:#000000;">5</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">037</span>            </span>g.drawLine(x, y, x - <span style="color:#000000;">20</span>, y + <span style="color:#000000;">5</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">038</span>            </span>g.drawLine(x - <span style="color:#000000;">20</span>, y - <span style="color:#000000;">5</span>, x - <span style="color:#000000;">20</span>, y + <span style="color:#000000;">5</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">039</span>            </span>y += <span style="color:#000000;">15</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">040</span>            </span><span style="color:#0000e6;">if</span> (y &gt; <span style="color:#000000;">550</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">041</span>            </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">042</span>                </span>y = nave.y;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">043</span>                </span>x += <span style="color:#000000;">15</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">044</span>            </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">045</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">046</span>        </span>g.setColor(Color.white);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">047</span>        </span>g.drawString(<span style="color:#ce7b00;">"Pulsos: "</span> + contador.getPulsosPorSegundo() +<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">048</span>                     </span><span style="color:#ce7b00;">"  Frames: "</span> + contador.getFramesPorSegundo() +<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">049</span>                     </span><span style="color:#ce7b00;">"          naves: "</span> + nave.qtd, <span style="color:#000000;">10</span>, <span style="color:#000000;">20</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">050</span>        </span>g.dispose();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">051</span>        </span>bs.show();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">052</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">053</span></span>}</pre>
<p>Veja que essas classes recebem &#8220;de fora&#8221;, no momento de sua construção, os objetos necessários para seu funcionamento. Ou seja, elas não possuem dados próprios, encapsulando apenas o algoritmo. Para que elas compartilhem os mesmos dados, criei também uma classe separada para armazenar os dados da nave:</p>
<p><strong>Arquivo Nave.java</strong></p>
<pre style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">package</span> abrindoojogo.exemplos.thread;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span></span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">class</span> Nave<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span></span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">005</span>    </span><span style="color:#0000e6;">int</span> x;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">006</span>    </span><span style="color:#0000e6;">int</span> y;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span>    </span><span style="color:#0000e6;">int</span> qtd;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span></span>}</pre>
<p>A classe do jogo em sí é exatamente igual à classe JogoLoopSimples vista em um artigo anterior, só que sem update() e sem render() e com o <em>gameloop</em> modificado conforme abaixo:</p>
<pre style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> gameloop()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span>        </span>initialize();<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">004</span>        </span></span><span style="color:#ff0000;">Controlador c = new Controlador(this, contador, nave);
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">005</span>        Renderizador r = new Renderizador(this, bs, contador, nave);</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">006</span>        </span><span style="color:#0000e6;">while</span> (<span style="color:#0000e6;">true</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span>        </span>{<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">008</span>            </span></span><span style="color:#ff0000;">c.update();
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">009</span>            r.render();</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">011</span>    </span>}</pre>
<p>Além disso, mais uma pequena modificação: ao sair do programa (pressionar ESC), envio para o console os dados de pulsos e frames, para registro. Isso é feito com um System.out.println() chamado na rotina keyPressed():</p>
<pre style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> keyPressed(KeyEvent e)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span>        </span><span style="color:#0000e6;">if</span> (e.getKeyCode() == KeyEvent.VK_ESCAPE)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span>        </span>{<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">005</span>            </span></span><span style="color:#ff0000;">System.out.println("Pulsos: " + contador.getPulsosPorSegundo() +
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">006</span>                                "  Frames: " + contador.getFramesPorSegundo() +
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">007</span>                                "          naves: " + nave.qtd);</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span>            </span>System.exit(<span style="color:#000000;">0</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">009</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span>        </span>...</pre>
<p style="text-align:left;">Executando o programa assim, temos o seguinte resultado:</p>
<p style="text-align:center;"><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread01a.png"><img class="size-full wp-image-864 aligncenter" title="Thread01a" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread01a.png" alt="Thread01a" width="502" height="214" /></a></p>
<p style="text-align:center;"><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread01b.png"><img class="size-full wp-image-865 aligncenter" title="Thread01b" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread01b.png" alt="Thread01b" width="279" height="222" /></a></p>
<p style="text-align:left;">Reconhece a tela? É o mesmo protótipo da nave dos outros posts. Mas perai&#8230; Uau! 460 fps! Não eram apenas 40! Como foi que ficou mais rápido?</p>
<p>Simples: troquei de máquina&#8230; Veja: essa é uma máquina bem mais rápida e tem um processador de dois núcleos como podemos ver no painel do gerenciador de tarefas. Note outra coisa também: apesar do jogo estar programado de forma a rodar o mais rápido possível (sem limitação de pulsos), ele utiliza apenas 50% do processamento da máquina. Nos gráficos pode-se ver claramente que o jogo está ocupando praticamente todo núcleo da esquerda, enquanto o da direita está ocioso (quase ocioso, na verdade, está atendendo o S.O. e processos de fundo, como o antivirus).</p>
<p>Abaixo da tela está a saída do console do NetBeans, mostrando o número de pulsos e frames registrados ao fechar o programa.</p>
<h2>A soma das partes</h2>
<p>Modifiquemos agora nosso gameloop <strong>comentando o update()</strong>. Assim vamos ver quantos frames conseguimos se eliminarmos o trabalho de atualizar a lógica do jogo.</p>
<p>A saída é a seguinte:</p>
<p><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread02a.png"><img class="aligncenter size-full wp-image-866" title="Thread02a" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread02a.png" alt="Thread02a" width="468" height="199" /></a></p>
<p><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread02b.png"><img class="aligncenter size-full wp-image-867" title="Thread02b" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread02b.png" alt="Thread02b" width="278" height="222" /></a>Veja que temos zero pulsos, já que update() nunca foi executada. Mas a quantidade de frames não mudou. Ou seja, o impacto de processamento da nossa lógica é muito pequeno. Vejamos o contrário. Vamos <strong>comentar o render()</strong>.</p>
<p>Resultado abaixo:</p>
<p><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread03a.png"><img class="aligncenter size-full wp-image-868" title="Thread03a" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread03a.png" alt="Thread03a" width="468" height="199" /></a><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread03b.png"><img class="aligncenter size-full wp-image-872" title="Thread03b" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread03b.png" alt="Thread03b" width="278" height="222" /></a>Pois é, sem o render() não aparece a tela. Mas o programa está lá, rodando, como podemos ver pelo processamento. Ao pressionar ESC basta olhar para a saída para ver a quantidade de pulsos e&#8230; Caraca! Mais de três milhões e meio de pulsos por segundo! Realmente, a parte (bem) mais pesada é a atualização da tela. A atualização da lógica (nesse caso, pelo menos) é tão efêmera que esse computador consegue realizar mais de 3.000.000 em um segundos contra apenas 460 atualizações da tela no mesmo tempo.</p>
<h2>Analisando os resultados, entram as Threads</h2>
<p>A primeira coisa importante é ver como o render() segura o jogo quando usamos esse tipo de <em>gameloop</em>, que é o mais simples. A cada volta do laço temos um update() (muito rápido) e um render(), que demora e faz com que o próximo update() acabe demorando a ser executado.</p>
<p>Mas o que conta para este post é o seguinte: reveja as imagens acima e preste atenção no processamento. Ele nunca passa de 50%. Ou seja, meu jogo não está tirando tudo da minha máquina nova! Praticamente ele só usa o núcleo da esquerda, enquanto o outro fica com pouco processamento, oriundo das tarefas do sistema. Isso é bom, na verdade. Mas e se eu precisasse de mais processamento? Teria uma forma de usar o outro núcleo? Tem sim, com <em>threads</em>.</p>
<p>Você sabe que o S.O. é multitarefa, ou seja, executa vários programas ao mesmo tempo. Você pode ver um vídeo e ouvir música ao mesmo simultâneamente, porque o S.O dá um pouco de processador para o vídeo e um pouco para a música. É a mesma CPU, porém dividida entre dois programas.</p>
<p>Se tem mais de uma CPU (mais de um núcleo, como na máquina acima), o S.O. pode dar um núcleo inteiro para o vídeo e o outro núcleo para a música, ao invés de dividir a mesma CPU. Isso torna as coisas mais ágeis ainda.</p>
<p>As <em>threads</em> permitem ter esta multitarefa dentro do mesmo programa. Por exemplo, você cria uma <em>thread</em> para carregar os dados do jogo e outra para rodar uma animação. Assim, o S.O. dá um pouco de processamento para cada uma,  e o resultado é que você pode mostrar uma animação enquanto os dados são carregados.</p>
<p>A modificação que faço a seguir no código vai permitir colocar o Controlador em uma <em>thread</em> e o Renderizador em outra, de forma a executarem paralelamente e, de quebra, rodar cada um em um núcleo, utilizando todo o poder da máquina. Se o render() sozinho dá 460 frames e update(), também sozinho, dá 3.000.000, agora deverei obter o jogo rodando simultâneamente com 3.000.000 pulsos e 460 frames.</p>
<p>Vamos ver se funciona:</p>
<pre style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">class</span> Controlador <span style="color:#ff0000;">implements Runnable</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span></span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span>    </span>Contador contador;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span>    </span>JFrame frame;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">005</span>    </span>Nave nave;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">006</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span>    </span><span style="color:#0000e6;">public</span> Controlador(JFrame frame, Contador contador, Nave nave)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">009</span>        </span><span style="color:#0000e6;">this</span>.frame = frame;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span>        </span><span style="color:#0000e6;">this</span>.contador = contador;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">011</span>        </span><span style="color:#0000e6;">this</span>.nave = nave;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">012</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">013</span>
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">014</span>    </span></span><span style="color:#ff0000;">public void run()
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">015</span>    {
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">016</span>        while (true)
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">017</span>        {
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">018</span>            Thread.yield();
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">019</span>            update();
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">020</span>        }
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">021</span>    }</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">022</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">023</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> update()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">024</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">025</span>        </span>...<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">026</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">027</span></span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">class</span> Renderizador <span style="color:#ff0000;">implements Runnable</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">028</span></span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">029</span>    </span>BufferStrategy bs;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">030</span>    </span>Contador contador;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">031</span>    </span>JFrame frame;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">032</span>    </span>Nave nave;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">033</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">boolean</span> terminado = <span style="color:#0000e6;">false</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">034</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">035</span>    </span><span style="color:#0000e6;">public</span> Renderizador(JFrame frame, BufferStrategy bs, Contador contador, Nave nave)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">036</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">037</span>        </span><span style="color:#0000e6;">this</span>.frame = frame;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">038</span>        </span><span style="color:#0000e6;">this</span>.bs = bs;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">039</span>        </span><span style="color:#0000e6;">this</span>.contador = contador;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">040</span>        </span><span style="color:#0000e6;">this</span>.nave = nave;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">041</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">042</span>
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">043</span>    </span></span><span style="color:#ff0000;">public void run()
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">044</span>    {
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">045</span>        while (!terminado)
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">046</span>        {
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">047</span>            Thread.yield();
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">048</span>            render();
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">049</span>        }
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">050</span>    }</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">051</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">052</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> render()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">053</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">054</span>        </span>...</pre>
<p>Modifiquei o código das classes Controlador e Renderizador para que implementem a interface Runnable do Java. Para isso, também declarei o método run() e dentro dele coloquei um laço. O Renderizador tem um laço que fica chamando render(). O Controlador tem um laço que fica chamando o update().</p>
<p>Agora a modificação no <em>gameloop</em>:</p>
<pre style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> gameloop()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span>        </span>initialize();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span>        </span>Controlador c = <span style="color:#0000e6;">new</span> Controlador(<span style="color:#0000e6;">this</span>, contador, nave);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">005</span>        </span>Renderizador r = <span style="color:#0000e6;">new</span> Renderizador(<span style="color:#0000e6;">this</span>, bs, contador, nave);<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">006</span>        </span></span><span style="color:#ff0000;">Thread t;
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">007</span>        t = new Thread(c);
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">008</span>        t.start();
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">009</span>        t = new Thread(r);
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">010</span>        t.start();</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">011</span>    </span>}</pre>
<p>Aqui está o uso das <em>threads</em>, finalmente. Basta criar um objeto do tipo Thread informando para ele um objeto do tipo Runnable (o Renderizador, por exemplo). Depois chamamos o método start() da <em>thread</em> e ela vai chamar o método run() do objeto que lhe foi passado. O método run() será executado em paralelo ao resto do programa. Então, estamos colocando o laço do render() e o laço do update() para rodarem em paralelo.</p>
<p>Curioso para ver o resutado? Está abaixo:</p>
<p><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread04a.png"><img class="aligncenter size-full wp-image-863" title="Thread04a" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/10/thread04a.png" alt="Thread04a" width="468" height="199" /></a></p>
<p>Voilá! Um milhão e oitocentos mil pulsos e 459 frames. E usado 100% da CPU. Veja que agora os dois núcleos estão absolutamente carregados &#8211; a linha do gráfico está &#8220;cravada&#8221; no topo.</p>
<p>Mas porque deu valores menores do que quando rodamos cada um separadamente? Bom, é que a CPU ainda precisa atender os tais processos de fundo, S.O., antivirus, etc. Eles devem estar rodando no mesmo núcleo do update(), o que fez ele executar mais lentamente. Mas foi uma boa escolha do S.O., já que esse é o processo mais leve. Inteligentes estas máquinas modernas, não?</p>
<p>De qualquer forma, é um desempenho muito acima da primeira versão que eu mostrei.</p>
<h2>Conclusão</h2>
<p>Não usem <em>threads</em>.</p>
<p>Pelo menos não até chegar a um ponto onde não tenha mais o quê otimizar no código de vocês e ainda assim o jogo esteja lento. Uma minoria de jogos atuais faz uso intensivo de <em>threads</em> (menos de 20, pelo que sei), e todos especialistas concordam que não é fácil.</p>
<p>O que fiz no código acima, compartilhar um objeto (a nave) entre duas <em>threads</em> rodando paralelamente é perigoso. Nesse caso uma delas atualiza os dados e a outra apenas lê. Mas se duas <em>threads</em> atualizarem os mesmos dados ao mesmo tempo, as consequencias serão imprevisíveis. O Java facilita porque possui formas de sincronizar dados, impedindo sua leitura simultaneamente por duas <em>threads</em>. Mas não adianta sincronizar tudo, senão uma <em>thread</em> vai acabar esperando pela outra para poder acessar os dados e vão acabar rodando em sequencia, ao invés de em paralelo.</p>
<p>Por outro lado, o Java, por sí,  já tira proveito de processadores de múltiplos núcleos. Existem outros processos que a máquina virtual faz, como coleta de lixo e otimização interativa do código. A JVM (Máquina Virtual Java) faz uso de <em>threads</em> para separar e rodar em paralelo estas operações, melhorando o desempenhdo do seu programa sem você ter que fazer nada.</p>
<p>Bom, fica aí um exemplo de uso de <em>threads</em> para quem não conhecia.</p>
<p><a href="http://blog.abrindoojogo.com.br/cursos/como-obter-os-codigos-fonte-dos-artigos/">Baixe o código fonte deste artigo.</a></p>
<div id="_mcePaste" style="overflow:hidden;position:absolute;left:-10000px;top:1850px;width:1px;height:1px;">&lt;pre style=&#8221;font-family:Monospaced,monospace;color:#000000&#8243;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;001&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;package&lt;/span&gt; abrindoojogo.exemplos.thread;&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;002&lt;/span&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;003&lt;/span&gt;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;public&lt;/span&gt; &lt;span style=&#8221;color:#0000e6;&#8221;&gt;class&lt;/span&gt; Nave&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;004&lt;/span&gt;&lt;/span&gt;{&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;005&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;int&lt;/span&gt; x;&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;006&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;int&lt;/span&gt; y;&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;007&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;int&lt;/span&gt; qtd;&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;008&lt;/span&gt;&lt;/span&gt;}&lt;/pre&gt;</div>
]]></content:encoded>
			<wfw:commentRss>http://www.abrindoojogo.com.br/2009/10/08/threads-apenas-um-exemplo/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>GameLoop com taxa constante de pulsos – parte 2 de 2</title>
		<link>http://www.abrindoojogo.com.br/2009/09/26/gameloop-com-taxa-constante-de-pulsos-%e2%80%93-parte-2-de-2/</link>
		<comments>http://www.abrindoojogo.com.br/2009/09/26/gameloop-com-taxa-constante-de-pulsos-%e2%80%93-parte-2-de-2/#comments</comments>
		<pubDate>Sat, 26 Sep 2009 02:18:00 +0000</pubDate>
		<dc:creator>Luiz Alessandro Nörnberg</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Técnico]]></category>

		<guid isPermaLink="false">http://blog.abrindoojogo.com.br/?p=743</guid>
		<description><![CDATA[No artigo anterior vimos o game loop em sua forma mais simples, que tem o problema de ter a taxa de pulsos e frames presas uma a outra. Isso faz o jogo correr mais lentamente em CPUs lentas e acelerar em CPU mais poderosas, impedindo uma velocidade estável em todas plataformas. Neste artigo veremos como [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/gameloop1.png"><img class="alignleft size-full wp-image-729" title="GameLoop" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/gameloop1.png" alt="GameLoop" width="200" height="150" /></a>No artigo anterior vimos o game loop em sua forma mais simples, que tem o problema de ter a taxa de pulsos e frames presas uma a outra. Isso faz o jogo correr mais lentamente em CPUs lentas e acelerar em CPU mais poderosas, impedindo uma velocidade estável em todas plataformas. Neste artigo veremos como criar um game loop que garanta uma velocidade fixa para o jogo.</p>
<p><span id="more-743"></span>Aprendemos, no post anterior, a diferença entre o pulso e o frame, sendo o primeiro relacionado à lógica do jogo e o segundo à atualização da tela. Tinhamos uma classe Main que criava um objeto do tipo JogoLoopSimples. Vamos modificar essa classe para usar agora um objeto do tipo JogoPulsoFixo.</p>
<p><strong>Arquivo Main.java</strong></p>
<pre><span style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">package</span> abrindoojogo.exemplos.gameloop;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span></span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">class</span> Main<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span></span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">005</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">static</span> <span style="color:#0000e6;">void</span> main(String[] args)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">006</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span>        </span>JogoPulsoFixo jogo = <span style="color:#0000e6;">new</span> JogoPulsoFixo();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span>        </span>jogo.gameloop();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">009</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span></span>}</span></pre>
<p>O game loop da classe JogoLoopSimples era assim (para relembrar):</p>
<pre><span style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> gameloop()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span>        </span>initialize();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span>        </span><span style="color:#0000e6;">while</span> (<span style="color:#0000e6;">true</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">005</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">006</span>            </span>Thread.yield();<span style="color:#000000;">
<strong><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span>            </strong></span><strong>update();</strong><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span>            </span>render();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">009</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span>    </span>}</span></pre>
<p>Uma chamada a update() e uma a render(), acopladas. Se render demora, update também demora e o jogo fica lento. Bem, vamos partir do seguinte pressuposto: <strong>é possível &#8220;aturar&#8221; uma taxa de frames baixa, mas uma taxa de pulsos baixa modifica a jogabilidade.</strong></p>
<p>Imagine um jogo onde uma nave se move um pixel por pulso. Se temos 60 pulsos por segundo, ao final de dois segundos a nave terá se movido 120 pixels. Mas se a taxa cair para 10 pulsos por segundo, em dois segundos a nave vai se mover apenas 20 pixels. E mais: se o computador for muito rápido, a taxa pode subir a 100 pulsos por segundo, e a nave vai andar 200 pixels em dois segundos. A jogabilidade é totalmente afetada.</p>
<p>A solução que apresento a seguir tenta manter a taxa de pulsos fixa, em detrimento da taxa de frames. Ou seja, se a máquina é lenta, priorizamos os pulsos e geramos os frames conforme der. Sempre teremos 60 pulsos por segundo, embora a taxa de frames possa cair para 10.</p>
<p>Isso causa o seguinte efeito: a nave vai se mover sempre 120 pixels em dois segundos, independente da velocidade da máquina. Mas se a máquina for lenta, a tela estará sendo atualizada apenas a 10 frames por segundo &#8211; o jogador vai ver a imagem quadro a quadro, mas a jogabilidade não fica tão comprometida, porque não há mudança na velocidade da ação.</p>
<p>E se a máquina for muito rápida, ainda assim ficaremos apenas com 60 pulsos por segundo, embora possamos estar obtendo 100 frames. A atualização da tela será bem rápida, o que é bom, e a nave continua se movendo na velocidade esperada.</p>
<p>Eu mostro abaixo a nova classe, chamada JogoPulsoFixo. Ela é derivada da classe do artigo anterior, de forma que tem tudo igual a ela. A lógica do jogo é exatamente a mesma. Só sobreescrevi o método gameloop, para modificá-lo.</p>
<p><strong>Arquivo JogoPulsoFixo.java</strong></p>
<pre><span style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">package</span> abrindoojogo.exemplos.gameloop;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span></span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">class</span> JogoPulsoFixo <span style="color:#0000e6;">extends</span> JogoLoopSimples<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span></span>{<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">005</span>    </span></span><span style="color:#ff0000;">long PULSOS_DESEJADOS_POR_SEGUNDO = 60;
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">006</span>    double NANOS_ESPERADOS_POR_PULSO = Contador.NANOS_EM_UM_SEGUNDO / PULSOS_DESEJADOS_POR_SEGUNDO;</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span>    </span>@Override<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">009</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> gameloop()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">011</span>        </span>initialize();<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">012</span>        </span></span><span style="color:#ff0000;">long nanoTimeDoProximoPulso = System.nanoTime();</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">013</span>        </span><span style="color:#0000e6;">while</span> (<span style="color:#0000e6;">true</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">014</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">015</span>            </span>Thread.yield();<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">016</span>            </span></span><span style="color:#ff0000;">while (System.nanoTime() &gt; nanoTimeDoProximoPulso)
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">017</span>            {
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">018</span>                update();
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">019</span>                nanoTimeDoProximoPulso += NANOS_ESPERADOS_POR_PULSO;
<span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">020</span>            }</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">021</span>            </span>render();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">022</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">023</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">024</span></span>}</span></pre>
<p>A modificação (marcada em vermelho) é simples em termos de código, mas pode ser difícil de entender como funciona. Por isso vou explicar bem detalhadamente.</p>
<p>Nas linhas 005, 006  são declaradas constantes. PULSOS_DESEJADOS_POR_SEGUNDO armazena a quantidade de pulsos que desejamos que o game rode. Nesse caso é 60. Não é necessário mais do que isso para a lógica de qualquer jogo. Alguns rodam a 30 ou 25.</p>
<p>NANOS_ESPERADOS_POR_PULSO armazena a quantidade de nanosegundos que cada pulso deve durar. Calcular isso é fácil: se queremos 60 pulsos por segundo, basta pegar a quantidade total de nanosegundos que cabem em um segundo (1e9 ou  1.000.000.000) e dividir por sessenta pulsos. Cada pulso vai durar, nesse caso, 16.666.666 nanosegundos. Em geral vai durar menos, mas queremos ter um pulso a cada 16.666.666 nanosegundos, de forma a constituir 60 por segundo.</p>
<p>Agora veja o game loop. A grande mudança é que temos um outro laço dentro dele, para chamar repetidamente update(). Funciona assim: inicializamos uma variável chamada nanoTimeDoProximoPulso com o valor no nanosegundo atual. Em seguida entramos no game loop e já caimos no loop do update. É feita a verificação para ver se o nanosegundo atual é maior do que o nanoTimeDoProximoPulso, o que certamente não será, já que acabamos de atribuir o tempo atual a esta variável.</p>
<p>Pois bem. Entramos no loop do update(), chamamos esta rotina e depois adicionamos ao nanoTimeDoProximoPulso a quantidade de nanos esperados em um pulso. Isso nos dá o momento no tempo quando deverá ser executado o próximo pulso. Não executaremos ele antes desse tempo. Por outro lado, passar muito desse tempo, executaremos ele mais de uma vez até recuperar o atraso.</p>
<p>Vamos analisar um exemplo volta a volta do game loop. Respire fundo antes de continuar lendo.</p>
<ol>
<li>Vamos assumir que tudo iniciou com o nanoTime = 0 (zero). Executamos update(), que demora 5.000.000 nanosegundos e somamos 16.666.666 na variável nanoTimeDoProximoPulso. Isso quer dizer que o próximo pulso é esperado para ocorrer nesse tempo.</li>
<li>Como update() demorou apenas 5.000.000 nanosegundos, ainda não chegamos ao 16.666.666 e saimos do loop do update. É executado em seguida o  render(), que demora mais 5.000.000 nanosegundos e voltamos ao início do game loop.</li>
<li>Nova verificação do loop do update. O tempo atual é maior do que 16.666.666? Já que update() levou 5.000.000 e render() mais 5.000.000, estamos em 10.000.000 nanosegundos, que é menor. Não entramos no loop do update, ou seja, desta vez o update() não será executado, porque ainda não está na hora esperada. Executamos o render(), que leva mais 5.000.000 nanosegundos e voltamos ao início do game loop.</li>
<li>Agora já estamos em 15.000.000, mas ainda é menor do que 16.666.666, então pulamos novamente o loop do update e vamos direto para o render. Mais 5.000.000 nanosegundos e voltamos ao início.</li>
<li>Agora sim, estamos em 20.000.000 nanosegundos e isso é maior do que o esperado para o próximo pulso, que deveria ter ocorrido em 16.666.666. Estamos atrasados, mas tudo bem &#8211; agora entramos no loop do update, executamos ele (mais 5.000.000) e somamos mais 16.666.666 na variável nanoTimeDoProximoPulso. Isso quer dizer que agora vamos esperar até o tempo chegar em 33.333.332 para executar update() novamente.</li>
</ol>
<p>Já deu para notar que update está sendo limitado. Praticamente temos três render() para cada update(). Essa é uma máquina rápida. Vamos refazer a análise em uma máquina lenta.</p>
<ol>
<li>Tudo inicia no nanoTime = 0 (zero). Executamos update(), que agora demora 10.000.000 nanosegundos e somamos 16.666.666 na variável nanoTimeDoProximoPulso.</li>
<li>Como update() demorou apenas 9.000.000 nanosegundos, ainda não chegamos ao 16.666.666 e saimos do loop do update. É executado em seguida o  render(), que demora 15.000.000 nanosegundos (placa de vídeo lenta) e voltamos ao início do game loop.</li>
<li>Nova verificação do loop do update e o tempo atual é 25.000.000, ou seja, maior que o 16.666.666 esperado para o próximo pulso. Assim, entramos no loop do update e executamos ele. Mais 10.000.000 se passam e estamos então há 35.000.000 nanosegundos de jogo. Acrescentamos novamente 16.666.666 à variável, ficando com 33.333.332, que seria a hora do próximo pulso.</li>
<li>Mas veja: já estamos em 35.000.000, ou seja, já passou a hora do segundo pulso. Então ficamos dentro do loop do update (porque 35.000.000 é maior que 33.333.332) e vamos executar update mais uma vez. Se passam mais 10.000.000 e estamos em 45.000.000. Somamos novamente 16.666.666 na variável e o próximo pulso fica então esperado para 49.999.998.</li>
<li>Ok, desta vez o tempo atual (45.000.000) é menor do que o esperado para o próximo pulso (49.999.998). Então pulamos o loop do update e vamos para o render(). Executamos ele e, devido aos seus 15.000.000 ficamos em 60.000.000 e voltamos ao início.</li>
</ol>
<p>Já deu para ver que vamos entrar novamente no loop do update porque estamos bem atrasados. Vamos acabar executando o update duas vezes novamente, ou seja, nessa máquina o update executa o dobro de vezes que o render.</p>
<p>Caramba, que explicação cheia de volta&#8230; Entendeu? Espero que sim. Caso contrário, leia novamente o exemplo. Experimente colocar o comando contador.sleep(X), onde X é um número de milisegundos, dentro das rotinas update() e render() no arquivo JogoLoopSimples. Isso vai simular rotinas demoradas. Use valores como 50 ou 100  milisegundos.</p>
<p>Esse game loop mantém a taxa de pulsos fixa (na verdade pode oscilar entre 60 e 62) e pode ser utilizado para a criação de games reais. Mas ele apresenta um problema com máquina muitissimo lentas: pode ser que o update() precise rodar 500 vezes para cada render(). Ou mais! Ou ainda, ficar rodando sem nunca chegar na taxa desejada, e assim nunca executar o update().</p>
<p>Alguma dica de como resolver isso? Se você achar uma solução envie para mim (<strong>nornberg</strong> no gmail). Depois publico um post citando as soluções que aparecerem.</p>
<p><a href="http://blog.abrindoojogo.com.br/cursos/como-obter-os-codigos-fonte-dos-artigos/">Baixe o código fonte deste artigo.</a></p>
<div id="_mcePaste" style="overflow:hidden;position:absolute;left:-10000px;top:786px;width:1px;height:1px;">&lt;pre&gt;&lt;span style=&#8221;font-family:Monospaced,monospace;color:#000000&#8243;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;001&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;package&lt;/span&gt; abrindoojogo.exemplos.gameloop;&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;002&lt;/span&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;003&lt;/span&gt;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;public&lt;/span&gt; &lt;span style=&#8221;color:#0000e6;&#8221;&gt;class&lt;/span&gt; JogoPulsoFixo &lt;span style=&#8221;color:#0000e6;&#8221;&gt;extends&lt;/span&gt; JogoLoopSimples&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;004&lt;/span&gt;&lt;/span&gt;{&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;005&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;long&lt;/span&gt; PULSOS_DESEJADOS_POR_SEGUNDO = &lt;span style=&#8221;color:#000000;&#8221;&gt;60&lt;/span&gt;;&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;006&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;double&lt;/span&gt; NANOS_ESPERADOS_POR_PULSO = Contador.NANOS_EM_UM_SEGUNDO / PULSOS_DESEJADOS_POR_SEGUNDO;&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;007&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;long&lt;/span&gt; MAX_FRAMES_PARA_PULAR = &lt;span style=&#8221;color:#000000;&#8221;&gt;2&lt;/span&gt;;&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;008&lt;/span&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;009&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;public&lt;/span&gt; &lt;span style=&#8221;color:#0000e6;&#8221;&gt;void&lt;/span&gt; gameloop()&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;010&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;011&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;initialize();&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;012&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;long&lt;/span&gt; nanoTimeDoProximoPulso = System.nanoTime();&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;013&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;while&lt;/span&gt; (&lt;span style=&#8221;color:#0000e6;&#8221;&gt;true&lt;/span&gt;)&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;014&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;015&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Thread.yield();&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;016&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;long&lt;/span&gt; pulsos = &lt;span style=&#8221;color:#000000;&#8221;&gt;0&lt;/span&gt;;&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;017&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&#8221;color:#0000e6;&#8221;&gt;while&lt;/span&gt; (System.nanoTime() &amp;gt; nanoTimeDoProximoPulso &amp;amp;&amp;amp; pulsos &amp;lt; MAX_FRAMES_PARA_PULAR)&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;018&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;019&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;update();&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;020&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;nanoTimeDoProximoPulso += NANOS_ESPERADOS_POR_PULSO;&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;021&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;pulsos++;&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;022&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;023&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;render();&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;024&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;025&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style=&#8221;color:#000000;&#8221;&gt;&lt;br/&gt;&lt;span style=&#8217;color:#666;background-color:#DDD;border-right:1px #999 solid;margin-right:5px;padding:2px&#8217;&gt;026&lt;/span&gt;&lt;/span&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;</div>
]]></content:encoded>
			<wfw:commentRss>http://www.abrindoojogo.com.br/2009/09/26/gameloop-com-taxa-constante-de-pulsos-%e2%80%93-parte-2-de-2/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>GameLoop com taxa constante de pulsos &#8211; parte 1 de 2</title>
		<link>http://www.abrindoojogo.com.br/2009/09/25/gameloop-com-taxa-constante-de-pulsos-parte-1-de-2/</link>
		<comments>http://www.abrindoojogo.com.br/2009/09/25/gameloop-com-taxa-constante-de-pulsos-parte-1-de-2/#comments</comments>
		<pubDate>Fri, 25 Sep 2009 03:31:02 +0000</pubDate>
		<dc:creator>Luiz Alessandro Nörnberg</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Técnico]]></category>

		<guid isPermaLink="false">http://blog.abrindoojogo.com.br/?p=727</guid>
		<description><![CDATA[
O coração de qualquer jogo é o game loop, um laço que fica sendo repetido durante toda execução do jogo. A cada volta desse laço temos um novo frame de jogo. Mas você sabe que a taxa de frames pode variar muito de um hardware para outro. Como manter a lógica do jogo rodando a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/gameloop1.png"><img class="alignleft size-full wp-image-729" title="GameLoop" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/gameloop1.png" alt="GameLoop" width="200" height="150" /></a></p>
<p>O coração de qualquer jogo é o <em>game loop</em>, um laço que fica sendo repetido durante toda execução do jogo. A cada volta desse laço temos um novo frame de jogo. Mas você sabe que a taxa de frames pode variar muito de um hardware para outro. Como manter a lógica do jogo rodando a uma velocidade fixa, independente da variação nos frames?<br />
<span id="more-727"></span><br />
Quando jogamos, o que vemos na tela é uma sucessão de quadros que nos dá a impressão de movimento. Isso é chamado animação e tenho certeza que você já conhece seus princípios. Em geral somos levados a crer que, a cada quadro novo que vemos, algo mudou no estado do jogo. Se uma nave está se movendo, a cada quadro ela estará, digamos, um pixel para a direita.</p>
<p>É o <em>game loop</em>, o laço principal do jogo, que emite o que podemos chamar de <strong>pulsos </strong>para atualizar o estado do jogo (<em><strong>update</strong></em>) e redesenhar a imagem na tela (<em><strong>render</strong></em>). Em sua forma mais simples, a cada volta do <em>game loop</em> temos um pulso para <em>update </em>e um para <em>render</em>. Mas estas duas tarefas não precisam ser sempre sincronizadas. Na verdade, é melhor que não sejam.</p>
<p>Vamos contruir um programa de exemplo para estudar mais a fundo o <em>game loop</em>. Neste post vamos ver o <em>loop </em>mais simples e entender sua limitação. No próximo veremos como desacoplar o <em>update </em>do <em>render</em>, de forma que o <em>update </em>rode sempre a uma determinada velocidade e o <em>render </em>rode o mais rápido que puder.</p>
<p><strong>Arquivo Main.java</strong></p>
<div style="overflow:scroll;border:1px solid #cccccc;">
<pre><span style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">package</span> abrindoojogo.exemplos.gameloop;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span></span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">class</span> Main<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span></span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">005</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">static</span> <span style="color:#0000e6;">void</span> main(String[] args)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">006</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span>        </span>JogoLoopSimples jogo = <span style="color:#0000e6;">new</span> JogoLoopSimples();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span>        </span>jogo.gameloop();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">009</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span></span>}</span></pre>
</div>
<p>Esta classe simplesmente cria um objeto do tipo JogoLoopSimples e chama seu método gameloop() que vai rodar o jogo. A seguir a classe do jogo em sí, que possui o game loop.</p>
<p><strong>Arquivo JogoLoopSimples</strong></p>
<div style="overflow:scroll;border:1px solid #cccccc;">
<pre><span style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">package</span> abrindoojogo.exemplos.gameloop;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span></span><span style="color:#0000e6;">import</span> java.awt.Color;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span></span><span style="color:#0000e6;">import</span> java.awt.Dimension;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">005</span></span><span style="color:#0000e6;">import</span> java.awt.Graphics2D;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">006</span></span><span style="color:#0000e6;">import</span> java.awt.Toolkit;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span></span><span style="color:#0000e6;">import</span> java.awt.event.KeyEvent;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span></span><span style="color:#0000e6;">import</span> java.awt.event.KeyListener;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">009</span></span><span style="color:#0000e6;">import</span> java.awt.image.BufferStrategy;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span></span><span style="color:#0000e6;">import</span> javax.swing.JFrame;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">011</span></span><span style="color:#0000e6;">import</span> javax.swing.WindowConstants;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">012</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">013</span></span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">class</span> JogoLoopSimples <span style="color:#0000e6;">extends</span> JFrame <span style="color:#0000e6;">implements</span> KeyListener<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">014</span></span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">015</span>    </span>BufferStrategy bs;<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">016</span>    </span></span><span style="color:#ff0000;">Contador contador;</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">017</span>    </span><span style="color:#0000e6;">int</span> nave_x, nave_y, nave_qtd;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">018</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">019</span>    </span><span style="color:#0000e6;">public</span> JogoLoopSimples()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">020</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">021</span>        </span>setUndecorated(<span style="color:#0000e6;">true</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">022</span>        </span>setSize(<span style="color:#000000;">800</span>, <span style="color:#000000;">600</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">023</span>        </span>Dimension d = Toolkit.getDefaultToolkit().getScreenSize();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">024</span>        </span>setLocation(d.width / <span style="color:#000000;">2</span> - <span style="color:#000000;">400</span>, d.height / <span style="color:#000000;">2</span> - <span style="color:#000000;">300</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">025</span>        </span>setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">026</span>        </span>setIgnoreRepaint(<span style="color:#0000e6;">true</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">027</span>        </span>addKeyListener(<span style="color:#0000e6;">this</span>);<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">028</span>        </span></span><span style="color:#ff0000;">contador = new Contador();</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">029</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">030</span>
<strong><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">031</span>    </strong></span><strong><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> gameloop()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">032</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">033</span>        </span>initialize();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">034</span>        </span><span style="color:#0000e6;">while</span> (<span style="color:#0000e6;">true</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">035</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">036</span>            </span>Thread.yield();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">037</span>            </span>update();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">038</span>            </span>render();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">039</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">040</span>    </span>}</strong><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">041</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">042</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> initialize()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">043</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">044</span>        </span>setVisible(<span style="color:#0000e6;">true</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">045</span>        </span>createBufferStrategy(<span style="color:#000000;">2</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">046</span>        </span>bs = getBufferStrategy();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">047</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">048</span>        </span>nave_x = <span style="color:#000000;">400</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">049</span>        </span>nave_y = <span style="color:#000000;">50</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">050</span>        </span>nave_qtd = <span style="color:#000000;">1</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">051</span>
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">052</span>        </span></span><span style="color:#ff0000;">contador.inicia();</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">053</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">054</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">055</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> update()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">056</span>    </span>{<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">057</span>        </span></span><span style="color:#ff0000;">contador.contaPulso();</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">058</span>        </span>nave_x += <span style="color:#000000;">1</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">059</span>        </span><span style="color:#0000e6;">if</span> (nave_x &gt; getWidth() + <span style="color:#000000;">30</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">060</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">061</span>            </span>nave_x = <span style="color:#000000;">0</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">062</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">063</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">064</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">065</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> render()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">066</span>    </span>{<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">067</span>        </span></span><span style="color:#ff0000;">contador.contaFrame();</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">068</span>        </span>Graphics2D g = (Graphics2D) bs.getDrawGraphics();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">069</span>        </span>g.setColor(Color.black);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">070</span>        </span>g.fillRect(<span style="color:#000000;">0</span>, <span style="color:#000000;">0</span>, getWidth(), getHeight());<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">071</span>        </span><span style="color:#0000e6;">int</span> x = nave_x;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">072</span>        </span><span style="color:#0000e6;">int</span> y = nave_y;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">073</span>        </span><span style="color:#0000e6;">for</span> (<span style="color:#0000e6;">int</span> i = <span style="color:#000000;">0</span>; i &lt; nave_qtd; i++)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">074</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">075</span>            </span>g.setColor(Color.yellow);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">076</span>            </span>g.drawLine(x, y, x - <span style="color:#000000;">20</span>, y - <span style="color:#000000;">5</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">077</span>            </span>g.drawLine(x, y, x - <span style="color:#000000;">20</span>, y + <span style="color:#000000;">5</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">078</span>            </span>g.drawLine(x - <span style="color:#000000;">20</span>, y - <span style="color:#000000;">5</span>, x - <span style="color:#000000;">20</span>, y + <span style="color:#000000;">5</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">079</span>            </span>y += <span style="color:#000000;">15</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">080</span>            </span><span style="color:#0000e6;">if</span> (y &gt; <span style="color:#000000;">550</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">081</span>            </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">082</span>                </span>y = nave_y;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">083</span>                </span>x += <span style="color:#000000;">15</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">084</span>            </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">085</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">086</span>        </span>g.setColor(Color.white);<span style="color:#000000;">
<span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">087</span></span>        </span>g.drawString(<span style="color:#ce7b00;">"Pulsos: "</span> + <span style="color:#ff0000;">contador.getPulsosPorSegundo()</span> + <span style="color:#ce7b00;">"  Frames: "</span> + <span style="color:#ff0000;">contador.getFramesPorSegundo()</span> + <span style="color:#ce7b00;">"          naves: "</span> + nave_qtd, <span style="color:#000000;">10</span>, <span style="color:#000000;">20</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">088</span>        </span>g.dispose();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">089</span>        </span>bs.show();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">090</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">091</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">092</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> keyPressed(KeyEvent e)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">093</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">094</span>        </span><span style="color:#0000e6;">if</span> (e.getKeyCode() == KeyEvent.VK_ESCAPE)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">095</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">096</span>            </span>System.exit(<span style="color:#000000;">0</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">097</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">098</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">099</span>        </span><span style="color:#0000e6;">if</span> (e.getKeyCode() == KeyEvent.VK_UP)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">100</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">101</span>            </span>nave_y -= <span style="color:#000000;">1</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">102</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">103</span>        </span><span style="color:#0000e6;">if</span> (e.getKeyCode() == KeyEvent.VK_DOWN)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">104</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">105</span>            </span>nave_y += <span style="color:#000000;">1</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">106</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">107</span>        </span><span style="color:#0000e6;">if</span> (e.getKeyCode() == KeyEvent.VK_RIGHT)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">108</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">109</span>            </span><span style="color:#0000e6;">if</span> (nave_qtd &lt; <span style="color:#000000;">1054</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">110</span>            </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">111</span>                </span>nave_qtd += <span style="color:#000000;">1</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">112</span>            </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">113</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">114</span>        </span><span style="color:#0000e6;">if</span> (e.getKeyCode() == KeyEvent.VK_LEFT)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">115</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">116</span>            </span><span style="color:#0000e6;">if</span> (nave_qtd &gt; <span style="color:#000000;">1</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">117</span>            </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">118</span>                </span>nave_qtd -= <span style="color:#000000;">1</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">119</span>            </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">120</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">121</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">122</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">123</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> keyReleased(KeyEvent e)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">124</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">125</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">126</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">127</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> keyTyped(KeyEvent e)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">128</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">129</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">130</span></span>}</span></pre>
</div>
<p>Vejamos os métodos mais importantes. O contructor faz bastante coisa de configuração, mas tudo com relação à janela do jogo. É tirada a decoração (título, borda, etc) ficando apenas um quadro centralizado no vídeo. É centralizado baseado no tamanho da tela, obtida por meio de Toolkit.getDefaultToolkit().getScreenSize().  Boa parte desse código é parecida com o que foi mostrado no post <a href="http://blog.abrindoojogo.com.br/2009/09/18/passive-vs-active-rendering-%E2%80%93-parte-2-de-2/">Passive VS Active Rendering</a>. Note, no entando na criação do objeto &#8220;contador&#8221;. Ele será utilizado para contar quantos pulsos e quantos <em>frames </em>obteremos. Os pontos onde ele é utilizado estão destacados em vermelho.</p>
<p>O jogo é muito simples &#8211; na verdade nem é um jogo. O método update() incrementa a variável nave_x, fazendo ela ir até a direita da tela e então recomeçar da esquerda. Quando uma tecla é pressionada, o método keyPressed modifica a variável nave_y, fazendo a posição subir ou descer, ou aumenta/diminui a variável nave_qtd, que informa quantos sprites teremos na tela.</p>
<p>O método render() limpa a tela, desenha a &#8220;nave&#8221; (um triângulo feito com linhas) dentro de um <em>loop </em>que vai repetir o desenho tantas vezes quanto for o valor de nave_qtd. Depois mostra na tela os valores de pulsos por segundo e <em>frames </em>por segundos do contador.</p>
<p>Note que toda vez que o método update() é executado, dentro dele é chamado o contador.contaPulso(). E no método render() é chamado contador.contaFrame(). Assim estamos contando quantas vezes estes dois métodos são chamados.</p>
<p>Nosso game loop é a versão mais simples possível, reproduzida abaixo.</p>
<div style="overflow:scroll;border:1px solid #cccccc;">
<pre><span style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">031</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> gameloop()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">032</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">033</span>        </span>initialize();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">034</span>        </span><span style="color:#0000e6;">while</span> (<span style="color:#0000e6;">true</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">035</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">036</span>            </span>Thread.yield();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">037</span>            </span>update();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">038</span>            </span>render();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">039</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">040</span>    </span>}</span></pre>
</div>
<p>É chamado update() e depois render(), um após o outro sem nenhum controle mais elaborado. O método yield() faz o programa interromper rapidamente seu processamento para que o resto do sistema tenha tempo de CPU. Usar ele faz o programa parar um pouco para escutar o teclado. Sem ele, um pressionar de tecla pode ser perdido.</p>
<p>Finalmente vejamos o código do contador.</p>
<p><strong>Arquivo Contador.java</strong></p>
<div style="overflow:scroll;border:1px solid #cccccc;">
<pre><span style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#0000e6;">package</span> abrindoojogo.exemplos.gameloop;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span></span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">class</span> Contador<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span></span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">005</span>    </span><span style="color:#0000e6;">static</span> <span style="color:#0000e6;">public</span> <span style="color:#0000e6;">double</span> NANOS_EM_UM_SEGUNDO = <span style="color:#000000;">1e9</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">006</span>    </span><span style="color:#0000e6;">protected</span> <span style="color:#0000e6;">long</span> pulsosPorSegundo;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span>    </span><span style="color:#0000e6;">protected</span> <span style="color:#0000e6;">long</span> framesPorSegundo;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span>    </span><span style="color:#0000e6;">protected</span> <span style="color:#0000e6;">long</span> nanoTimeAnterior;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">009</span>    </span><span style="color:#0000e6;">protected</span> <span style="color:#0000e6;">long</span> pulsosContados;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span>    </span><span style="color:#0000e6;">protected</span> <span style="color:#0000e6;">long</span> framesContados;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">011</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">012</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> inicia()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">013</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">014</span>        </span>nanoTimeAnterior = System.nanoTime();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">015</span>        </span>pulsosContados = <span style="color:#000000;">0</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">016</span>        </span>framesContados = <span style="color:#000000;">0</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">017</span>        </span>pulsosPorSegundo = <span style="color:#000000;">0</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">018</span>        </span>framesPorSegundo = <span style="color:#000000;">0</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">019</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">020</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">021</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> contaPulso()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">022</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">023</span>        </span>pulsosContados++;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">024</span>        </span>verifica();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">025</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">026</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">027</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> contaFrame()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">028</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">029</span>        </span>framesContados++;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">030</span>        </span>verifica();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">031</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">032</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">033</span>    </span><span style="color:#0000e6;">protected</span> <span style="color:#0000e6;">void</span> verifica()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">034</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">035</span>        </span><span style="color:#0000e6;">if</span> (System.nanoTime() - nanoTimeAnterior &gt; NANOS_EM_UM_SEGUNDO)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">036</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">037</span>            </span>pulsosPorSegundo = pulsosContados;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">038</span>            </span>framesPorSegundo = framesContados;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">039</span>            </span>pulsosContados = <span style="color:#000000;">0</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">040</span>            </span>framesContados = <span style="color:#000000;">0</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">041</span>            </span>nanoTimeAnterior = System.nanoTime();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">042</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">043</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">044</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">045</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> sleep(<span style="color:#0000e6;">long</span> miliSecondsToSleep)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">046</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">047</span>        </span><span style="color:#0000e6;">try</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">048</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">049</span>            </span>Thread.sleep(miliSecondsToSleep);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">050</span>        </span>} <span style="color:#0000e6;">catch</span> (Exception e)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">051</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">052</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">053</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">054</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">055</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">long</span> getPulsosPorSegundo()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">056</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">057</span>        </span><span style="color:#0000e6;">return</span> pulsosPorSegundo;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">058</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">059</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">060</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">long</span> getFramesPorSegundo()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">061</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">062</span>        </span><span style="color:#0000e6;">return</span> framesPorSegundo;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">063</span>    </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">064</span></span>}</span></pre>
</div>
<p>O trabalho desta classe é interessante: cada vez que chamamos o método contaPulso(), ela incrementa o contador de pulsos e chama o método verifica() que testa se já passou um segundo desde a última verificação. Se sim, ele atribui a quantidade de pulsos contados para a variável pulsosPorSegundo. Assim, esta variável é atualizada a cada segundo com a quantidade de pulsos que ocorreram. Nesse momento o contador de pulsos é zerado para contar quantos pulsos ocorrerão no próximo segundo. A mesma coisa para a contagem de frames.</p>
<p>O tempo é medido em nanosegundos, que é bem menor que os milisegundos geralmente utilizados nos programas. Um segundo contém 1.000 milisegundos, ou seja, <strong>1e3</strong> (mil). E possui 1.000.000.000 nano segundos, ou seja, <strong>1e9</strong> (um milhão). Esse valor está registrado na constante NANOS_EM_UM_SEGUNDO para ser utilizado nos cálculos.</p>
<p>Essa classe oferece ainda um método utilitário chamado sleep(), que servirá para realizarmos alguns testes. Ele simplifica o uso do método sleep() de Thread, que precisa de um <em>try-catch</em> para ser usado. Ele faz o processamento parar durante os milisegundos informados.</p>
<p>Executando esse programa, obtenho o seguinte resultado (só mostro o canto da tela):</p>
<p><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/gameloop01.png"><img class="aligncenter size-full wp-image-732" title="GameLoop01" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/gameloop01.png" alt="GameLoop01" width="400" height="100" /></a>Conforme os dados do contador mostrados, tenho 47 pulsos por segundo e também 47 frames. Naturalmente estes números serão sempre iguais, porque dentro do loop chamo uma vez update() e uma vez o render().</p>
<p>Se eu desejasse 60 fps (<em>frames </em>por segundo), não seria possível. 47 é tudo que eu consigo no meu computador e ainda fica variando. Se eu pressiono a seta para direita, aumentando a quantidade de <em>sprites </em>até 1054, a taxa de <em>frames </em>cai mais um pouco.</p>
<p><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/gameloop02.png"><img class="aligncenter size-full wp-image-733" title="GameLoop02" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/gameloop02.png" alt="GameLoop02" width="400" height="100" /></a>Talvez seu computador seja bem mais rápid e mesmo aumentando os <em>sprites </em>a taxa de frames não apresente muita diferença. Vamos fazer um teste mais exagerado. Chamaremos o método contador.sleep() dentro do método render(), de forma a fazer este método demorar alguns milisegundos a mais.</p>
<div style="overflow:scroll;border:1px solid #cccccc;">
<pre><span style="font-family:Monospaced,monospace;color:#000000;"><span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">001</span><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">002</span>
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">003</span>    </span><span style="color:#0000e6;">public</span> <span style="color:#0000e6;">void</span> render()<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">004</span>    </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">005</span>        </span>contador.contaFrame();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">006</span>        </span>Graphics2D g = (Graphics2D) bs.getDrawGraphics();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">007</span>        </span>g.setColor(Color.black);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">008</span>        </span>g.fillRect(<span style="color:#000000;">0</span>, <span style="color:#000000;">0</span>, getWidth(), getHeight());<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">009</span>        </span><span style="color:#0000e6;">int</span> x = nave_x;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">010</span>        </span><span style="color:#0000e6;">int</span> y = nave_y;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">011</span>        </span><span style="color:#0000e6;">for</span> (<span style="color:#0000e6;">int</span> i = <span style="color:#000000;">0</span>; i &lt; nave_qtd; i++)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">012</span>        </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">013</span>            </span>g.setColor(Color.yellow);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">014</span>            </span>g.drawLine(x, y, x - <span style="color:#000000;">20</span>, y - <span style="color:#000000;">5</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">015</span>            </span>g.drawLine(x, y, x - <span style="color:#000000;">20</span>, y + <span style="color:#000000;">5</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">016</span>            </span>g.drawLine(x - <span style="color:#000000;">20</span>, y - <span style="color:#000000;">5</span>, x - <span style="color:#000000;">20</span>, y + <span style="color:#000000;">5</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">017</span>            </span>y += <span style="color:#000000;">15</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">018</span>            </span><span style="color:#0000e6;">if</span> (y &gt; <span style="color:#000000;">550</span>)<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">019</span>            </span>{<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">020</span>                </span>y = nave_y;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">021</span>                </span>x += <span style="color:#000000;">15</span>;<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">022</span>            </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">023</span>        </span>}<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">024</span>        </span>g.setColor(Color.white);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">025</span>        </span>g.drawString(<span style="color:#ce7b00;">"Pulsos: "</span> + contador.getPulsosPorSegundo() + <span style="color:#ce7b00;">"  Frames: "</span> + contador.getFramesPorSegundo() + <span style="color:#ce7b00;">"          naves: "</span> + nave_qtd, <span style="color:#000000;">10</span>, <span style="color:#000000;">20</span>);<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">026</span>        </span>g.dispose();<span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">027</span>        </span>bs.show();<span style="color:#000000;">
<strong><span style="color:#ff0000;"><span style="border-right:1px solid #999999;background-color:#dddddd;margin-right:5px;padding:2px;">028</span>        </span></strong></span><strong><span style="color:#ff0000;">contador.sleep(50);</span></strong><span style="color:#000000;">
<span style="color:#666;background-color:#ddd;border-right:1px #999 solid;margin-right:5px;padding:2px;">029</span>    </span>}</span></pre>
</div>
<p>Agora sim. O tempo de atualizar a tela (render) leva absurdos 50 ms (milisegundos). Absolutamente lento demais. A taxa de <strong>frames </strong>cai para 14 na minha máquina.</p>
<p><a href="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/gameloop03.png"><img class="aligncenter size-full wp-image-734" title="GameLoop03" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/gameloop03.png" alt="GameLoop03" width="400" height="100" /></a>Agora preste atenção na parte mais importante: <strong>a taxa de pulsos por segundo cai junto com os frames</strong>, embora apenas a rotina render() tenha recebido o tempo a mais. Isso ocorre porque como uma rotina é chamada depois da outra, em sequencia, update() tem que esperar render() executar para ser executada novamente.</p>
<p>Rodando o jogo você percebe que não é apenas a taxa de atualização da tela que fica lenta, <strong>mas o jogo todo</strong>. A nave agora leva uma eternidade para chegar até a extremidade da tela, porque temos apenas 14 pulsos de atualização da sua posição por segundo.</p>
<p>Está comprovado o problema. No próximo post a solução. Até amanhã.</p>
<p><a href="http://blog.abrindoojogo.com.br/cursos/como-obter-os-codigos-fonte-dos-artigos/">Baixe o código fonte deste artigo.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.abrindoojogo.com.br/2009/09/25/gameloop-com-taxa-constante-de-pulsos-parte-1-de-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Passive VS Active Rendering – parte 2 de 2</title>
		<link>http://www.abrindoojogo.com.br/2009/09/18/passive-vs-active-rendering-%e2%80%93-parte-2-de-2/</link>
		<comments>http://www.abrindoojogo.com.br/2009/09/18/passive-vs-active-rendering-%e2%80%93-parte-2-de-2/#comments</comments>
		<pubDate>Fri, 18 Sep 2009 01:59:53 +0000</pubDate>
		<dc:creator>Luiz Alessandro Nörnberg</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Técnico]]></category>

		<guid isPermaLink="false">http://blog.abrindoojogo.com.br/?p=680</guid>
		<description><![CDATA[Vimos no post anterior a atualização passiva e suas limitações. Vejamos agora coisa real, criando um programa com maior previsibilidade na atualização da tela, capacidade de rodar em tela-cheia (fullscreen) e de mudar o modo de vídeo.  Para isso aprenderemos a atualização ativa (active rendering).
Atualização ativa
No artigo anterior vimos a atualização passiva que pode ser [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-689" title="FullScreen" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/fullscreen1.png" alt="FullScreen" width="199" height="150" />Vimos no post anterior a atualização passiva e suas limitações. Vejamos agora coisa real, criando um programa com maior previsibilidade na atualização da tela, capacidade de rodar em tela-cheia (<em>fullscreen</em>) e de mudar o modo de vídeo.  Para isso aprenderemos a atualização ativa (<em>active rendering</em>).<span id="more-680"></span></p>
<h2>Atualização ativa</h2>
<p>No artigo anterior vimos a <a href="http://blog.abrindoojogo.com.br/2009/09/17/passive-vs-active-rendering-parte-1-de-2/">atualização passiva</a> que pode ser utilizada para a criação de jogos que possuem gráficos simples ou ação lenta. E nestes casos é até recomendada, porque compromete pouco a CPU. Mas em jogos mais animados não podemos depender do S.O. para gerar as atualizações da tela. Nesse caso desligamos o mecanismo de atualização automatica e partimos para o manual, com a atualização ativa.</p>
<p>O Java nos permite controlar a tela de forma deterministica por meio da classe BufferStrategy. Não é um acesso direto à placa de vídeo, porque o Java nos isola da camada de hardware. Mas isso é bom, porque simplifica a coisa e nos oferece uma forma padrão para trabalhar, o mais independente possível da configuração da máquina do usuário.</p>
<p>Abaixo mostro o código de um programa quase idêntico ao do artigo anterior, porém agora usando atualização ativa.</p>
<h3>Arquivo: Main.java</h3>
<pre><span class="line-number"> 1</span> <span class="keyword-directive">package</span> abrindoojogo.exemplos.atualizacaoativa;
<span class="line-number"> 2</span>
<span class="line-number"> 3</span> <span class="keyword-directive">public</span> <span class="keyword-directive">class</span> Main
<span class="line-number"> 4</span> {
<span class="line-number"> 5</span>     <span class="keyword-directive">public</span> <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> main(String[] args)
<span class="line-number"> 6</span>     {
<span class="line-number"> 7</span>         MeuJogo mj = <span class="keyword-directive">new</span> MeuJogo();
<span class="line-number"> 8</span>         mj.setVisible(<span class="keyword-directive">true</span>);
<span class="line-number"> 9</span>         mj.initialize();
<span class="line-number">10</span>     }
<span class="line-number">11</span> }
<span class="line-number">12</span>
<span class="line-number">13</span></pre>
<p>Veja que a classe principal é quase igual. A diferença é que a classe MeuJogo agora possui um método initialize que deve ser chamado depois de tornarmos ela visível. Nesse método inicializamos a BufferStrategy (veja abaixo). Destaquei em vermelho as partes que são novidade em relação ao exemplo anterior.</p>
<h3>Arquivo: MeuJogo.java</h3>
<pre><span class="line-number"> 1</span> <span class="keyword-directive">package</span> abrindoojogo.exemplos.atualizacaoativa;
<span class="line-number"> 2</span>
<span class="line-number"> 3</span> <span class="keyword-directive">import</span> java.awt.Color;
<span class="line-number"> 4</span> <span class="keyword-directive">import</span> java.awt.Graphics2D;
<span class="line-number"> 5</span> <span class="keyword-directive">import</span> java.awt.event.KeyEvent;
<span class="line-number"> 6</span> <span class="keyword-directive">import</span> java.awt.event.KeyListener;
<span class="line-number"> 7</span> <span class="keyword-directive">import</span> java.awt.image.BufferStrategy;
<span class="line-number"> 8</span> <span class="keyword-directive">import</span> javax.swing.JFrame;
<span class="line-number"> 9</span> <span class="keyword-directive">import</span> javax.swing.WindowConstants;
<span class="line-number">10</span>
<span class="line-number">11</span> <span class="keyword-directive">public</span> <span class="keyword-directive">class</span> MeuJogo <span class="keyword-directive">extends</span> JFrame <span class="keyword-directive">implements</span> KeyListener
<span class="line-number">12</span> {
<span class="line-number">13</span>     <span class="keyword-directive">in</span><span class="keyword-directive">t</span> tom;
<span style="color:#ff0000;"><span class="line-number">14</span>     BufferStrategy bs;
</span><span class="line-number">15</span>
<span class="line-number">16</span>     <span class="keyword-directive">public</span> MeuJogo()
<span class="line-number">17</span>     {
<span class="line-number">18</span>         setTitle(<span class="character">"</span><span class="character">Atualização Ativa</span><span class="character">"</span>);
<span class="line-number">19</span>         setSize(800, 600);
<span class="line-number">20</span>         setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
<span style="color:#ff0000;"><span class="line-number">21</span>         setIgnoreRepaint(<span class="keyword-directive">true</span>);</span>
<span class="line-number">22</span>         addKeyListener(<span class="keyword-directive">this</span>);
<span class="line-number">23</span>         tom = 0;
<span class="line-number">24</span>     }
<span class="line-number">25</span>
<span style="color:#ff0000;"><span class="line-number">26</span>     <span class="keyword-directive">public</span> <span class="keyword-directive">void</span> initialize()
<span class="line-number">27</span>     {
<span class="line-number">28</span>         createBufferStrategy(1);
<span class="line-number">29</span>         bs = getBufferStrategy();
<span class="line-number">30</span>         render();
<span class="line-number">31</span>     }</span>
<span class="line-number">32</span>
<span style="color:#ff0000;"><span class="line-number">33</span>     <span class="keyword-directive">public</span> <span class="keyword-directive">void</span> render()</span>
<span class="line-number">34</span>     {
<span style="color:#ff0000;"><span class="line-number">35</span>         Graphics2D g = (Graphics2D) bs.getDrawGraphics();</span>
<span class="line-number">36</span>         g.clearRect(0, 0, getWidth(), getHeight());
<span class="line-number">37</span>         <span class="keyword-directive">for</span> (<span class="keyword-directive">int</span> x = 0; x &lt; 800; x += 10)
<span class="line-number">38</span>         {
<span class="line-number">39</span>             <span class="keyword-directive">for</span> (<span class="keyword-directive">int</span> y = 0; y &lt; 600; y += 10)
<span class="line-number">40</span>             {
<span class="line-number">41</span>                 g.setColor(<span class="keyword-directive">new</span> Color(x % 256, y % 256, (tom * 50)
                   % 256));
<span class="line-number">42</span>                 g.fillRect(x, y, 10, 10);
<span class="line-number">43</span>             }
<span class="line-number">44</span>         }
<span style="color:#ff0000;"><span class="line-number">45</span>         g.dispose();
<span class="line-number">46</span>         bs.show();</span>
<span class="line-number">47</span>     }
<span class="line-number">48</span>
<span class="line-number">49</span>     <span class="keyword-directive">public</span> <span class="keyword-directive">void</span> keyPressed(KeyEvent e)
<span class="line-number">50</span>     {
<span class="line-number">51</span>         <span class="keyword-directive">if</span> (e.getKeyCode() == KeyEvent.VK_ENTER)
<span class="line-number">52</span>         {
<span class="line-number">53</span>             tom++;
<span style="color:#ff0000;"><span class="line-number">54</span>             render();</span>
<span class="line-number">55</span>         }
<span class="line-number">56</span>     }
<span class="line-number">57</span>
<span class="line-number">58</span>     <span class="keyword-directive">public</span> <span class="keyword-directive">void</span> keyReleased(KeyEvent e)
<span class="line-number">59</span>     {
<span class="line-number">60</span>     }
<span class="line-number">61</span>
<span class="line-number">62</span>     <span class="keyword-directive">public</span> <span class="keyword-directive">void</span> keyTyped(KeyEvent e)
<span class="line-number">63</span>     {
<span class="line-number">64</span>     }
<span class="line-number">65</span> }
<span class="line-number">66</span>
<span class="line-number">67</span></pre>
<p>O contructor é muito parecido, mas preste atenção. Ele inclui agora uma chamada ao método <strong>setIgnoreRepaint() </strong>passando o valor true. Isso desliga a atualização automática. O S.O. não vai mais gerar eventos de atualização para nossa janela.</p>
<p>Em seguida temos o método initialize().</p>
<pre>26     public void initialize()
27     {
28         createBufferStrategy(1);
29         bs = getBufferStrategy();
30         render();
31     }</pre>
<p>Nesse método eu chamo <strong>createBufferStrategy()</strong>, que é pertencente à classe JFrame. O parâmetro é a quantidade de buffers de tela que quero usar. Falarei sobre isso adiante. Adquiro uma referência ao BufferStratey e armazeno na variável bs. Através desta variável eu vou ter acesso ao buffer da tela para desenhar meus gráficos. Logo após chamo o método render().</p>
<p>O método render() é o próximo declarado na classe. É nele que se dá o desenho da tela. Veja que é praticamente o mesmo código que estava dentro do método paint() do artigo anterior. Só que agora é um método próprio e não um manipulador de evento. Lembre que desligamos a atualização automática, que chamava o paint(). O método render(), por sua vez, será chamado diretamente por mim, quando eu desejar que a tela seja redesenhada.</p>
<pre>33     public void render()
34     {
35         Graphics2D g = (Graphics2D) bs.getDrawGraphics();
36         g.clearRect(0, 0, getWidth(), getHeight());
37         for (int x = 0; x &lt; 800; x += 10)
38         {
39             for (int y = 0; y &lt; 600; y += 10)
40             {
41                 g.setColor(new Color(x % 256, y % 256, (tom * 50)
                   % 256));
42                 g.fillRect(x, y, 10, 10);
43             }
44         }
45         g.dispose();
46         bs.show();
47     }</pre>
<p>Examinando esse método, vemos que a parte que lida com o objeto &#8220;g&#8221;, do tipo Graphics2D, é idêntica à anterior. A diferença está no modo como obtemos o Graphics. Antes ele era recebido como parâmetro no método paint(). Ou seja, o S.O. nos passava o Graphics ao chamar o método. Agora nós pegamos um Graphics do objeto BufferStrategy. Esse Graphics que ele retorna é uma referência para o buffer da tela, desenhando nele, desenhamos nela. Depois de usar, chamamos o método dispose para liberar &#8211; adquirimos e liberamos um novo Graphics a cada render.</p>
<p>Depois do desenho pronto, chamamos o método show() do BufferStrategy. Embora nesse momento ele fique um pouco perdido, vai fazer mais sentido quando eu falar em mais de um buffer, daqui a pouco.</p>
<p>A modificação final é no método keyPressed(), que é o manipulador para o evento de tecla pressionada. Depois de atualizar a variável &#8220;tom&#8221;, chamamos render(). Aqui reside a grande diferença: enquanto antes chamavamos repaint() para avisar o S.O. que desejávamos uma atualização, e ficava a cargo dele atualizar a tela quando bem entendesse, agora chamamos diretamente nosso método render(), que vai obter um Graphics e desenhar na hora, sem espera.</p>
<p>Execute esse programa e o resultado vai ser parecido com o anterior, na parte visual. Quando você ficar pressionando ENTER a tela vai piscar da mesma forma, porém a atualização da tela consome mais CPU e por isso se você ficar pressionando por muito tempo, os eventos keyPressed não vão ser processados a tempo e vão acumular (ao soltar a tecla continuarão sendo gerados eventos por algum tempo).</p>
<p>Note também que redimensionando a janela ela não é mais redesenhada. Não há mais eventos relacionado a essa ação.</p>
<h2>DoubleBuffer</h2>
<p>Para evitar as piscadas na tela (o efeito chamado de <em>tearing</em> &#8211; rasgo), utilizaremos dois buffers ao invés de um. A lógica é a seguinte: se temos apenas um buffer, ele está sempre sendo mostrado na tela. Quando desenhamos nele, o desenho é feito diretamente nela e podemos ver o desenho sendo contruído e reconstruído repetidamente. Isso causa o efeito indesejado.</p>
<p>Se utilizarmos dois buffers, enquanto um deles é mostrado na tela, desenhamos no outro. Assim, enquanto o desenho está sendo contruído, nós estamos olhando para o desenho anterior, que está estático. Quando o novo desenho está pronto, o método show() do BufferStrategy troca os buffers. Aquele que acabamos de atualizar vai para a tela e o outro passa a ser o de desenho. E ficamos nessa, sempre desenhando no buffer de trás (<em>back buffer</em>) enquanto o outro (<em>front buffer</em> ou buffer primário) fica estático na tela. Como a troca de buffers é muito rápida, centenas de vezes mais rápida do que gerar um desenho na tela, não ocorre nenhum efeito perceptível para o usuário.</p>
<p>Para usar dois buffers, basta mudar o parâmetro do método createBufferStrategy(). Passe o número 2 ao invés de 1 e execute o programa. As piscadas sumirão. Você pode usar mais buffers, mas isso torna o processo mais lento e consome bem mais memória &#8211; veja, cada buffer é uma cópia da tela, seria como ter três telas na memória de vídeo. E memória de vídeo é algo que não podemos desperdiçar. Apenas em casos muito específicos, ou em determinados hardwares, o uso de triplebuffer traz melhorias e pode ser usado. Mais de três buffers, nem pensar &#8211; você pode até passar um número maior, mas provavelmente serão criados apenas 2 ou 3.</p>
<p>Observação: dependendo do seu hardware, a troca de buffers pode ser feita de formas diferentes, o que gera resultados melhores para uns do que para outros. De qualquer forma a diferença deste exemplo para o anterior será gritante.</p>
<h2>Fullscreen e mudança de modo de vídeo</h2>
<p>Que tal rodar o jogo em tela-cheia? Essa é melhor opção porque cria uma imersão muito mais profunda para o usuário, melhorando sua experiência com o jogo. Mas só tela-cheia não basta por causa do tamanho da tela. Se seu jogo foi feito em 800&#215;600 (como é o caso desse exemplo), colocar em tela-cheia vai fazer ele não ocupar toda tela, ficando uma borda preta ao redor. Em um monitor com resolução de 1440, o jogo fica sendo apenas um quadro no meio da tela.</p>
<p>Para usar tela-cheia, o ideal, então, é mudar o modo de vídeo do monitor para ajustar-se à resolução do jogo. Mudando o modo de vídeo para 800&#215;600 o jogo ocupa todo monitor, sem bordas.</p>
<p>Fazer isso é bem fácil. Veja abaixo o método initialize modificado para colocar a janela em tela-cheia e logo após mudar o modo de vídeo para 800&#215;600.</p>
<pre><span class="line-number">28</span>     <span class="keyword-directive">pub</span><span class="keyword-directive">lic</span> <span class="keyword-directive">void</span> initialize()
<span class="line-number">29</span>     {
<span class="line-number">30</span>         createBufferStrategy(1);
<span class="line-number">31</span>         bs = getBufferStrategy();
<span style="color:#ff0000;"><span class="line-number">32</span>         getGraphicsConfiguration().getDevice().
           setFullScreenWindow(<span class="keyword-directive">this</span>);
<span class="line-number">33</span>         getGraphicsConfiguration().getDevice().setDisplayMode(<span class="keyword-directive">
           new</span> DisplayMode(800, 600, 32,
           DisplayMode.REFRESH_RATE_UNKNOWN));</span>
<span class="line-number">34</span>         render();
<span class="line-number">35</span>     }
<span class="line-number"> </span></pre>
<p>Utilizei o método <strong>getGraphicsConfiguration() </strong>herdado da classe JFrame para, através dele, obter acesso ao dispositivo de vídeo (getDevice). A classe GraphicsDevice nos provê um método para entrar em tela-cheia, que é setFullScreenWindow(). Passamos para ele a janela que vai ocupar a tela &#8211; nesse caso, nossa própria classe, que é uma janela. Passando null para esse método saimos da tela-cheia, o que também ocorre, automaticamente, ao fecharmos o programa.</p>
<p>Outro método que temos à disposição é o <strong>setDisplayMode()</strong>. Passamos para ele um objeto do tipo DisplayMode, criado com os dados do modo de vídeo desejado. Os primeiros dois parâmewtros são largura e altura (800&#215;600). Em seguida a profundidade de cor, ou seja, quantos bits por cor. No caso, passei 32 bits &#8211; hoje todos monitores suportam isso. O último parâmetro é a taxa de atualização do monitor (<em>refresh rate</em>). Por exemplo, pode ser 60, 70, 80, etc, onde 60 significa 60Hz e assim por diante. Mas essa taxa não é padronizada e por isso é melhor utilizar a constante <strong>DisplayMode.REFRESH_RATE_UNKNOWN</strong>, que não muda a taxa de atualização do monitor.</p>
<p>Executando o programa assim, ele entra ela tela-cheia. Mas ainda fica com a borda da janela, o que não é desejado nesse caso. Programas em tela-cheia não exibem a borda. Para esconder ela, basta chamar o método <strong>setUndecorated() </strong>passando true. Isso tira a decoração da janela (borda, título, botões). Veja abaixo como chamei esse método no contructor.</p>
<pre>17     public MeuJogo()
18     {
19         setTitle("Atualização Ativa");
20         setSize(800, 600);
<span style="color:#ff0000;">21         setUndecorated(true);</span>
22         setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
23         setIgnoreRepaint(true);
24         addKeyListener(this);
25         tom = 0;
26     }</pre>
<p>Pronto, agora temos um programa que roda em tela-cheia, mudando a resolução do vídeo e sem piscar ao atualizar a tela. Além de termos a garantia de que a tela vai ser atualizada sempre que mandarmos.</p>
<p>Mas para evoluir até um jogo, falta um detalhe importante! Você notou que a coisa só se &#8220;mexe&#8221; quando pressionamos ENTER. Isso porque é dentro do evento do teclado (keyPressed) que modificamos a variável e atualizamos a tela. Um jogo real fica modificando seu estado e atualizando a tela sozinho, sem ninguém pressionar um tecla. Para isso temos que ter um loop em algum lugar &#8211; o fatídico <em>game loop</em>. Assunto para o próximo post.</p>
<p>Até lá, pensem na melhor forma de fazer isso. Que tal fazer esse programa ficar mudando as cores sem estar o ENTER pressionado? Mãos à obra.</p>
<p><a href="http://blog.abrindoojogo.com.br/cursos/como-obter-os-codigos-fonte-dos-artigos/">Baixe o código fonte deste artigo.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.abrindoojogo.com.br/2009/09/18/passive-vs-active-rendering-%e2%80%93-parte-2-de-2/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Passive VS Active Rendering &#8211; parte 1 de 2</title>
		<link>http://www.abrindoojogo.com.br/2009/09/17/passive-vs-active-rendering-parte-1-de-2/</link>
		<comments>http://www.abrindoojogo.com.br/2009/09/17/passive-vs-active-rendering-parte-1-de-2/#comments</comments>
		<pubDate>Thu, 17 Sep 2009 02:00:35 +0000</pubDate>
		<dc:creator>Luiz Alessandro Nörnberg</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Técnico]]></category>

		<guid isPermaLink="false">http://blog.abrindoojogo.com.br/?p=653</guid>
		<description><![CDATA[Existem basicamente duas formas de atualizar a tela quando criamos um programa em Java. Podemos fazer isso de forma passiva ou ativa. Cada uma tem suas vantagens e desvantagens e veremos, nesta dupla de artigos, como implementá-las. Iniciaremos pela atualização passiva (passive rendering).
Atualização passiva
Esta é forma padrão de atualização de tela para programas em Java, [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-687" title="Repaint" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/repaint.png" alt="Repaint" width="200" height="150" />Existem basicamente duas formas de atualizar a tela quando criamos um programa em <strong>Java</strong>. Podemos fazer isso de forma passiva ou ativa. Cada uma tem suas vantagens e desvantagens e veremos, nesta dupla de artigos, como implementá-las. Iniciaremos pela atualização passiva (<em>passive rendering</em>).<span id="more-653"></span></p>
<h2>Atualização passiva</h2>
<p>Esta é forma padrão de atualização de tela para programas em Java, geralmente utilizada por aplicativos. É comum se ouvir falar que esta forma não serve para jogos, mas isto não é inteiramente verdade. Como tudo nessa vida, isso depende.</p>
<p>A atualização passíva consiste em criar uma rotina que é chamada pelo sistema operacional (S.O.) sempre que ele precisar de uma versão atualizada da nossa tela. Em termos técnicos criamos um manipulador de evento (<em>event handler</em>) para o evento Paint.</p>
<p>Veja que é o S.O. que decide quando a atualização é necessária, baseado em dados que ele possui e não baseado em dados do jogo em sí. Esta é sua maior limitação. Por outro lado, é uma forma muito leve em termos de processamento, já que a tela vai ser atualizada apenas quando for necessário e esta é sua vantagem.</p>
<p>Mas baseado em quê o sistema decide se precisa ou não atualizar a tela? Fundamentalmente em mudanças na área da tela como redimensionamento ou ocultamento/reapresentação.</p>
<p>Por exemplo, se nossa tela é uma janela, o sistema vai requerer uma atualização dela sempre que a mesma for redimensionada ou for ocultada e depois mostrada novamente. Nesses eventos é que precisamos desenhar novamente o conteúdo da tela. Veja a ilutração a seguir.</p>
<div id="attachment_703" class="wp-caption aligncenter" style="width: 462px"><a title="Clique para ampliar" href="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/interface-021.jpg" target="_blank"><img class="size-full wp-image-703" title="interface 02" src="http://aoj.ramspaiva.com/wp-content/uploads/2009/09/interface-021.jpg" alt="interface 02" width="452" height="139" /></a><p class="wp-caption-text">clique para ampliar</p></div>
<p style="text-align:left;">Vejamos como implementar isso em Java, usando uma janela do tipo Swing. Criamos uma classe chamada MeuJogo que é derivada da classe JFrame (um frame &#8211; moldura &#8211; é como chamamos uma janela em Java).</p>
<h3>Arquivo: MeuJogo.java</h3>
<pre><span class="line-number"> 1</span> <span class="keyword-directive">package</span> abrindoojogo.exemplos.atualizacaopassiva;
<span class="line-number"> 2</span>
<span class="line-number"> 3</span> <span class="keyword-directive">import</span> java.awt.Color;
<span class="line-number"> 4</span> <span class="keyword-directive">import</span> java.awt.Graphics;
<span class="line-number"> 5</span> <span class="keyword-directive">import</span> java.awt.event.KeyEvent;
<span class="line-number"> 6</span> <span class="keyword-directive">import</span> java.awt.event.KeyListener;
<span class="line-number"> 7</span> <span class="keyword-directive">import</span> javax.swing.JFrame;
<span class="line-number"> 8</span> <span class="keyword-directive">import</span> javax.swing.WindowConstants;
<span class="line-number"> 9</span>
<span class="line-number">10</span> <span class="keyword-directive">public</span> <span class="keyword-directive">class</span> MeuJogo <span class="keyword-directive">extends</span> JFrame <span class="keyword-directive">implements</span> KeyListener
<span class="line-number">11</span> {
<span class="line-number">12</span>     <span class="keyword-directive">int</span> tom;
<span class="line-number">13</span>
<span class="line-number">14</span>     <span class="keyword-directive">public</span> MeuJogo()
<span class="line-number">15</span>     {
<span class="line-number">16</span>         setTitle(<span class="character">"</span><span class="character">Atualização Passiva</span><span class="character">"</span>);
<span class="line-number">17</span>         setSize(800, 600);
<span class="line-number">18</span>         setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
<span class="line-number">19</span>         addKeyListener(<span class="keyword-directive">this</span>);
<span class="line-number">20</span>         tom = 0;
<span class="line-number">21</span>     }
<span class="line-number">22</span>
<span class="line-number">23</span>     @Override
<span class="line-number">24</span>     <span class="keyword-directive">public</span> <span class="keyword-directive">void</span> paint(Graphics g)
<span class="line-number">25</span>     {
<span class="line-number">26</span>         g.clearRect(0, 0, getWidth(), getHeight());
<span class="line-number">27</span>         <span class="keyword-directive">for</span> (<span class="keyword-directive">int</span> x = 0; x &lt; 800; x += 10)
<span class="line-number">28</span>         {
<span class="line-number">29</span>             <span class="keyword-directive">for</span> (<span class="keyword-directive">int</span> y = 0; y &lt; 600; y += 10)
<span class="line-number">30</span>             {
<span class="line-number">31</span>                 g.setColor(<span class="keyword-directive">new</span> Color(x % 256, y % 256, (tom * 50) % 256));
<span class="line-number">32</span>                 g.fillRect(x, y, 10, 10);
<span class="line-number">33</span>             }
<span class="line-number">34</span>         }
<span class="line-number">35</span>     }
<span class="line-number">36</span>
<span class="line-number">37</span>     <span class="keyword-directive">public</span> <span class="keyword-directive">void</span> keyPressed(KeyEvent e)
<span class="line-number">38</span>     {
<span class="line-number">39</span>         <span class="keyword-directive">if</span> (e.getKeyCode() == KeyEvent.VK_ENTER)
<span class="line-number">40</span>         {
<span class="line-number">41</span>             tom ++;
<span class="line-number">42</span>         }
<span class="line-number">43</span>     }
<span class="line-number">44</span>
<span class="line-number">45</span>     <span class="keyword-directive">public</span> <span class="keyword-directive">void</span> keyReleased(KeyEvent e)
<span class="line-number">46</span>     {
<span class="line-number">47</span>
<span class="line-number">48</span>     }
<span class="line-number">49</span>
<span class="line-number">50</span>     <span class="keyword-directive">public</span> <span class="keyword-directive">void</span> keyTyped(KeyEvent e)
<span class="line-number">51</span>     {
<span class="line-number">52</span>
<span class="line-number">53</span>     }
<span class="line-number">54</span> }</pre>
<p>Abaixo o código da classe principal do programa, onde o processamento inicia. Nela criamos um objeto do tipo da classe MeuJogo e fazemos ele ficar visível. Assim a janela aparece na tela.</p>
<h3>Arquivo: Main.java</h3>
<pre><span class="line-number"> 1</span> <span class="keyword-directive">package</span> abrindoojogo.exemplos.atualizacaopassiva;
<span class="line-number"> 2</span>
<span class="line-number"> 3</span> <span class="keyword-directive">public</span> <span class="keyword-directive">class</span> Main
<span class="line-number"> 4</span> {
<span class="line-number"> 5</span>     <span class="keyword-directive">public</span> <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> main(String[] args)
<span class="line-number"> 6</span>     {
<span class="line-number"> 7</span>         MeuJogo mj = <span class="keyword-directive">new</span> MeuJogo();
<span class="line-number"> 8</span>         mj.setVisible(<span class="keyword-directive">true</span>);
<span class="line-number"> 9</span>     }
<span class="line-number">10</span> }</pre>
<p>Faça o seguinte teste: execute esse exemplo e arraste o canto inferior direito da janela, redimensionando-a. Você vai notar que a imagem pisca: isso é porque está sendo redesenhada a cada alteração de tamanho. Faça isso bem rapidamente e você poderá notar que a imagem deixa de piscar por alguns instantes. Isso ocorre porque o sistema fica sobrecarregado com a mudança de tamanho e, para poupar CPU, deixa de atualziar a imagem, aguardando você parar de mover o mouse para, só então, gerar o evento de redesenho.</p>
<p>Experimente també ficar pressionando a tecla ENTER. Nada ocorre, embora tenhamos um manipulador para o evento KeyPressed que incrementa a variável &#8220;tom&#8221;, que é utilizada para determinar a cor do gráfico. Porque a cor do gráfico não muda?</p>
<p>O que ocorre é que nosso modelo, digamos assim, ou seja, a representação interna do gráfico mudou (a variável foi incrementada), mas como o S.O não sabe disso, ele não enviou o evento para atualziar a tela e por isso a imagem permanece igual. Para contornar isso basta chamar o método repaint() dentro do evento keyPressed. Veja abaixo.</p>
<pre>37     public void keyPressed(KeyEvent e)
38     {
39         if (e.getKeyCode() == KeyEvent.VK_ENTER)
40         {
41             tom ++;
<span style="color:#ff0000;">42             repaint();</span>
43         }
44     }</pre>
<p>Esse método informa ao S.O. que desejamos uma atualização da tela. Rode o programa agora a fique pressionando ENTER. Agora sim, a cor do gráfico muda. Pronto, temos uma máquina simples que serve como base para um jogo de pouca ação. Por exemplo, jogos de tabuleiro como batalha naval.</p>
<p>Porque não serve para jogos de ação intensa e animações constantes? Porque não temos controle sobre quando a tela será atualizada e porque tudo pisca (você notou que o gráfico piscar ao ficar pressionando ENTER?).</p>
<p>Colocar a chamada ao método repaint não faz a tela ser atualizada na hora. Apenas informa ao S.O. que queremos uma atualização, mas o S.O. pode demorar até alguns segundos para atualizar. Se for um jogo de ação, digamos de luta, o modelo interno do jogo vai ser atualizado várias vezes até que a tela seja redesenhada. Ou seja, seu oponente pode lhe dar um chute, você  perder energia e o oponente voltar a posição normal, tudo isso antes da próxima atualização da tela. Quando a tela for redesenhada, você vai ver que sua energia diminuiu, mas não viu o que aconteceu.</p>
<p>E, é claro, tem o problema de piscar. Como estamos atualizando diretamente a tela, ocorre o efeito de <em>tearing</em> (rasgo), onde parece que a imagem fica rasgada. Explicarei porque isso ocorre em um próximo post.</p>
<p>Mas para jogos lentos, quase parando, essa é uma boa opção porque consome muito pouco da CPU. Por exemplo, se for um jogo de damas. Você só precisa chamar o repaint() quando um dos jogadores mover uma peça, o que ocorre com pouca frequência. Não terá o efeito de ficar piscando.</p>
<p>Durante muito tempo isso foi tudo que podia ser feito em Java. Mas já alguns anos que a linguagem permite o que chamamos de <em>active rendering</em>. Esse recurso possibilita atualização instantânea da tela, a cada frame e de quebra nos oferece <em>double buffer</em> (o fim das piscadas), tela-cheia e até mudança de modo de vídeo. Veremos tudo isso amanhã, nesse mesmo site, nesse mesmo horário.</p>
<p><a href="http://blog.abrindoojogo.com.br/cursos/como-obter-os-codigos-fonte-dos-artigos/">Baixe o código fonte deste artigo.</a></p>
<address>Ilustrações: Inara Cavichioli</address>
<address><a href="http://blog.abrindoojogo.com.br/2009/09/18/passive-vs-active-rendering-%E2%80%93-parte-2-de-2/">Confira a segunda parte&gt;&gt;</a></address>
]]></content:encoded>
			<wfw:commentRss>http://www.abrindoojogo.com.br/2009/09/17/passive-vs-active-rendering-parte-1-de-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
