Você está na página 1de 306

Python & BGE

Criando jogos com o Blender

Brutto AVT (criação)


Cerberus_1746 (revisão)
Antes de começar...
Tudo tem que começar em
algum lugar, certo? Basta
analisar a imagem ao lado para
ver a evolução de alguns jogos
clássicos.

É bem provável que você se


lembre de alguns desses.
Talvez lembre até mesmo de
fases inteiras.
Antes de começar...
Este é o primeiro Super Mario, que
podia ser jogado num NES lá por
1985.

Mesmo sendo de gráficos simples,


o jogo consegue te prender na
frente da tela por algum tempo.

Por que? Simplesmente pelo fato


de que ele foi muito bem planejado
e desenvolvido.
Definindo um objetivo
Você não pode criar algo e esperar
que vá dar certo, se não tiver uma
idéia bem clara do que pretende
fazer.

Ao processo de definição de um
projeto é dado o nome de pré-
produção ou planejamento.
Definindo um objetivo
Antes de qualquer coisa, faça uma
pergunta a si mesmo:

"Qual o meu objetivo?"

É isso que o guiará até o final do


projeto. Caso as coisas comecem a
ficar confusas, basta se lembrar do
seu objetivo inicial.

Portanto, devemos ter algumas


coisas em mente.
Dando forma ao objetivo

Qual o estilo do meu jogo? Plataforma, luta, RPG, corrida,


futebol...

Qual será meu público alvo? Jogadores casuais, jogadores


freqüentes, jogadores hardcore...

Os inimigos ou adversários terão inteligência artificial?

Qual o tamanho do meu jogo? Ele será dividido por fases?

O jogador pode escolher qual fase quer jogar? Será um


jogo multiplayer?
Dando forma ao objetivo

O que mais?
Pense por alguns minutos nas características básicas...
Dando forma ao objetivo
Também é necessário fazer um
planejamento mais detalhado. Pode não
parecer, mas isso nos economizará
tempo no futuro.

A idéia é, basicamente, que quando mais


tempo se gasta planejando, menos
tempo é necessário para desenvolver e
corrigir erros.

Ou você realmente acha que Cabral


descobriu o Brasil por acidente?
Um planejamento mais elaborado
Nesta etapa preciamos ser bem mais
precisos do que fomos no
planejamento inicial.

Ao final desta etapa, deveremos


saber exatamente o que e como
fazer.

Portanto, agora você deve pensar


nos desafios que o jogador irá
enfrentar, quem e como serão os
inimigos, como serão os cenários,
etc...
Coletando recursos
Muitas vezes não temos tempo ou
menos habilidade para criar a
trilha sonora, as texturas, etc.

Nesses casos, o melhor é tirar


proveito de bibliotecas (legais) de
sons, imagens, etc. Eis algumas
que recomendo:

http://www.grungetextures.com/ (texturas)
http://www.jamendo.com/br/ (músicas)
http://www.blender-materials.org/ (materiais)
http://e2-productions.com/repository/index.
php (modelos)
http://opengameart.org/ (mix)
Pronto? Ainda não!
Agora que temos o plano
completo (espero que sim), eu
devo lhe fazer uma pergunta:

Você sabe programar (de


preferência em Python)?

Caso já tenha conhecimento,


pule alguns slides, caso
contrário devo lhe apresentar a
uma coisa chamada Lógica de
Progamação antes disso.
Lógica de programação

A definição de "lógica", segundo o dicionário Michaelis:

"1 Modo de raciocinar tal como de fato se exerce:Lógica natural. 2 Filos Estudo que tem
por objeto determinar quais as operações que são válidas e quais as que não o são:
Lógica formal, que trata dos conceitos, juízos e raciocínios, independentemente de seu
conteúdo. Mais modernamente, análise das formas e leis do pensamento, seja do ponto
de vista racionalista e crítico, seja daquele em que se descreve a experiência: Lógica
genética, lógica das ciências, lógica simbólica, lógica matemática."
Lógica de programação

Logo, lógica de programação refere-se a como fazer as coisas


acontecerem, seguindo por caminhos dedutivamente corretos
(verdadeiros).

Resumindo: lógica é dedução. Agora, não podemos confundir


dedução com adivinhação ou tentativa e erro. Dedução é um
processo racional, no qual temos um conjunto de
possibilidades e, usando nosso conhecimento, vamos
eliminando as que acharmos serem incorretas até sobrarem
uma ou mais.

No caso de sobrar mais do que uma, vamos sempre pela


melhor opção.
Lógica de programação

Um exemplo: quem é o irmão do pai da mãe da minha


sobrinha?

Se você respondeu "meu tio", parabéns! Você atende ao


requerimento mínimo necessário para se tornar um
programador: saber pensar logicamente.

Vamos analisar um pouco sua resposta. Como você tem


certeza de que é seu tio e não seu avô? Ora, pelo seu
conhecimento! Você sabe a definição de sobrinho, pai, mãe e
irmão, certo?
Lógica de programação

Agora outro exemplo: como proceder para trocar uma


lâmpada?

A resposta pode variar de pessoa pra pessoa, pois graças a


Deus somos todos diferentes e também raciocinamos de jeitos
diferentes. A base de tudo? Conhecimento e experiência!

O que sua experiência e/ou conhecimento sobre trocas de


lâmpadas lhes mandam responder? Bem, os meus dizem o
seguinte...
Lógica de programação

1. Certificar-se de que o interruptor está desligado


2. Subir numa cadeira/escada para alcançar o bocal
3. Remover a lâmpada queimada
4. Colocar a lâmpada nova
5. Descer da cadeira/escada
6. Ligar o interruptor

Ao processo de definir algo de acordo com os próprios


conhecimentos ou a necessidade do projeto dá-se o nome de
abstração.
Lógica de programação
Já ouviu falar em arte abstrata?
Aquele monte de borrões que
ninguém entende?

Bem, arte abstrata nada mais é do


que o conceito do artista sobre
determinado assunto. Como eu
disse, todos pensam de forma
diferente, assim como todos definem
as coisas de modo diferente também.

Em resumo: abstração é a sua


definição para uma determinada
situação, objeto, etc.
Lógica de programação

Na minha abstração sobre a troca da lâmpada, eu não levei em


conta possíveis problemas que possam acontecer. Dê uma
olhada:

1. Certificar-se de que o interruptor está desligado (se não


estiver, desligar)
2. Subir numa cadeira/escada para alcançar o bocal
3. Remover a lâmpada queimada
4. Colocar a lâmpada nova
5. Descer da cadeira/escada
6. Ligar o interruptor
Lógica de programação

Notou a diferença no primeiro passo? Eu impus uma condição


para que a troca continuasse, já que ninguém gosta de levar
choque.

Outra situação seria esta:

Subir numa cadeira/escada para alcançar o bocal. Se não


alcançar, procurar um objeto mais alto para subir.

Notou que conforme avançamos no raciocínio, estamos


dividindo nosso problema em problemas menores?
Lógica de programação

Não se programa algo de uma vez só num único e gigantesco


código. Isso não funcionaria de verdade!

É por isso que é tão importante separar nosso problema maior


em pequenos problemas, agrupá-los e resolvê-los um a um.

Você pode não ter percebido, mas foi exatamente isso que
fizemos no planejamento do nosso jogo. Tratamos as coisas
separadamente de forma a cobrir nosso jogo completo.

Entretando, não acaba por aí. Como vamos fazer para carregar
a fase correta que o jogador escolher em nosso jogo, por
exemplo?
Lógica de programação

Depois dessa breve introdução ao raciocínio lógico, estamos


prontos para começar a pensar como programadores de
verdade.

Senhoras e senhores, lhes apresento o fluxograma!


Lógica de programação
Um fluxograma, nada mais é do
que uma representação visual de
um processo lógico.

Ele nos ajuda a ter uma noção


melhor da nossa própria linha de
raciocínio.

Embora não iremos utilizar


fluxogramas no nosso projeto, é
bom saber o que cada símbolo
representa.
Lógica de programação

Terminal: indica o início e o fim do processo

Entrada ou Saída: troca de dados com usuário

Processo: cálculo ou processamento de dados

Condição: compara valores e devolve "sim" ou "não"

Conexão: ligação de dois pontos no fluxograma

Sabendo isso, veja se consegue entender o fluxograma do


slide anterior.
Lógica de programação

Existem mais alguns símbolos, mas por hora, os que vimos já


estão de bom tamanho para que possamos seguir adiante.

Além da representação visual (fluxograma), também é possível


fazer uma representação textual de um processo. A esse texto
damos o nome de algoritmo.

Finalmente, um algoritmo que é criado conforme uma


linguagem de programação é chamado código-fonte.
Lógica de programação

Os algoritmos obedecem a alguns padrões básicos que iremos


ver nos próximos slides, por hora quero que lembre de algo
que foi visto anteriormente:

"Subir numa cadeira/escada para alcançar o bocal. Se não


alcançar, procurar um objeto mais alto para subir."

Como pode-se notar, temos uma condição para que o


processo continue. Nos algoritmos, condições são
representadas pela palavra Se.
Lógica de programação

Logo, o fragmento de algoritmo do exemplo ficaria assim:

faça (Subir numa cadeira/escada para alcançar o bocal);


Se (não alcançar) então
faça (procurar um objeto mais alto para subir);
Fim Se;

As primeiras regras aqui são:


1. Nomes reservados (Se, então) sempre em destaque
2. Parâmetros para o Se sempre entre parênteses
3. Todo Se, deve ser terminado com um então
4. Toda instrução deve terminar com ponto e vírgula
5. Vamos deixar o Fim Se para mais tarde...
Lógica de programação

O termo "nomes reservados" refere-se a todas as palavras que


fazem parte do conjunto de comandos. Você não poderia ter
uma ação (função) chamada "Se", já que esta palavra é
reservada.

Alguns desses comandos são funções, ou seja, eles recebem


valores de entrada, os processam e retornam um valor de
saída. Esse é o caso do Se. Os valores de entrada são
chamados parâmetros.

Note que o Se não termina com ponto e vírgula, pois ele não é
uma instrução e sim uma condição.
Lógica de programação

Antes de continuar, é necessário que conheçamos os tipos de


dados básicos que podemos utilizar. São eles:

Inteiro (-1, 0, 1, 2, ...)


Decimal (-1.5, 0.2, 1.55, ...)
Caracteres ('a', '$', 'blá blá blá', ...)
Lógicos (Verdadeiro, Falso)

Com esses tipos de dados chamados "primitivos" e um pouco


de conhecimento das regras (sintaxe) dos algoritmos, podemos
criar processos bastante complexos.
Lógica de programação

De nada adianta poder trabalhar com vários tipos de dados, se


não temos como guardá-los, certo? É aí que entram as
variáveis.

Lembra-se do X da matemática? Podemos fazer uma analogia


dele com as variáveis dos algoritmos. Assim como na
matemática, ela não precisa se chamar necessariamente 'X'.

Podemos dar qualquer nome a uma variável, desde que esteja


dentro das regras, é claro!
Lógica de programação

Inteiro x = 2;
Inteiro y = 3;
Inteiro z = x + y;

Esse fragmento cria três variáveis do tipo inteiro: x, y e z,


sendo que x é igual a 2, y é igual a 3 e z é igual a soma de x e
y.

A regra aqui é:
Sempre colocar o tipo de dado antes do nome da variável,
usar o símbolo de igualdade para atribuir o valor e terminar
com ponto e vírgula.
Lógica de programação

Inteiro x = 2;
Inteiro xis = x;
Caractere letraA = 'a';
Lógico mentira = Falso;
Decimal real = 1.45;

Mais algumas regras:


1. Nome de variável sempre em letra minúscula. Caso seja
composto, não usar espaços e sim a primeira letra da outra
palavra em maiúscula.
2. Caso seja do tipo Decimal, não usar vírgula, mas sim ponto
para indicar o valor decimal.
Lógica de programação

Já estamos quase perto de fazer nosso primeiro algoritmo


completo. Só nos falta saber como eles começam e terminam.

As palavras são Início e Fim. Tudo o que estiver entre isso é


chamado de "bloco". Lembra do Fim Se? Pois bem, agora vou
explicá-lo.

O algoritmo com um todo é chamado de "bloco principal" (o


processo em si), entretanto o Se também deve ser seguido por
um bloco, pois ele deve ter algo para executar caso a condição
informada seja verdadeira. Quando a condição é falsa, ele
simplesmente pula esse bloco.
Lógica de programação

Eis um algoritmo completo:

Início Algoritmo
Inteiro a = 10;
Se (a > 10) então
Escreva (a, " é maior do que 10");
Fim Se
Fim Algoritmo

Note que o bloco Se não tem um Início. A regra diz que o início
do bloco Se é a palavra então. Outra regra é: exceto para o
bloco principal (Algoritmo), toda instrução dentro de bloco deve
ser identada (4 espaços em branco, ou 1 tabulação antes).
Lógica de programação

Outra coisa inédita:


Escreva (a, " é maior do que 10");

A função Escreva é responsável por dizer algo ao usuário. No


caso que o valor da variável 'a' é maior que 10.

Quando se quer colocar uma variável junto ao retorno (entre


aspas) para o usuário, é necessário separá-la do resto da
saída com uma vírgula.
Lógica de programação

Igualmente temos:
Leia (a);

Essa função é responsável por atribuir à variável 'a' um valor


informado pelo usuário. O valor antido de 'a' será substituído
pelo novo.
Lógica de programação

É possível agrupar várias estruturas de condição, por exemplo:

Se (a > 10) então


Escreva (a, " é maior que 10");
Fim Se
Senão
Se (a > 5) então
Escreva (a, " é maior que 5");
Fim Se
Senão
Escreva (a, " não é maior que 5 ou 10);
Fim Senão
Fim Senão
Lógica de programação

Também é possível agrupar várias condições dentro de um


mesmo Se. Neste caso, elas serão comparadas pelos
operadores e e ou.

Se (a == b e b == 2) então
Se (a ==b ou b == 2) então

O operador e soma duas condições, ou seja, ambas tem que


ser verdadeiras para que o Se seja verdadeiro. No ou, basta
que apenas uma das duas seja verdadeira.
Lógica de programação

O Senão é o bloco que representa o falso Se, ou seja, caso o


Se retorne falso, o bloco Senão será executado.

Pela regra, devemos usar o Senão apenas para um Se e logo


depois dele, ou seja, o Senão deve vir logo depois do Fim Se.

Pode-se também combinar os dois para obter condições mais


complexas.
Lógica de programação

Se (a > 10) então


Escreva (a, " é maior que 10");
Fim Se
Senão Se (a > 5) então
Escreva (a, " é maior que 5");
Fim Senão Se
Senão
Escreva (a, " é menor que 5 ou 10");
Fim Senão

Esse trecho faz exatamente a mesma coisa que o anterior.


Note que Senão Se não é nem Se, nem Senão, mas sim uma
nova palavra.
Lógica de programação

E se quiséssemos saber se a é maior ou igual a 10? Pois bem,


lhe apresento os operadores:

Atribuição (a = 10): atribui um valor a uma variável


Igualdade (a == 10): compara se dois valores são iguais
Maior (a > 10): compara se um valor é maior que outro
Menor (a < 10): compara se um valor é menor que outro
Maior ou igual (a >= 10): compara se um valor é maior ou
igual a outro
Menor ou igual (a <= 10): compara se um valor é menor ou
igual a outro
Diferença (a != 10): compara se um valor é diferente do
outro.
Lógica de programação

Uma coisa importante a esclarecer: o operador de diferença


não existe de verdade!

Ele é, na realidade, o operador de igualdade com retorno


invertido. É isso que o operador de negação (!) faz. inverte o
valor de uma variável do tipo Lógica.

Supondo que a seja igual a 10, temos:

a == 10 é igual a Verdadeiro
a != 10 é igual a Falso
Lógica de programação

Mais uma regra de algoritmos:

Enquanto (a < 10) faça


a = a - 1;
Escreva (a);
Fim Enquanto

Isso é uma estrutura de repetição que irá subtrair 1 do valor de


'a' e mostrar o valor atual para o usuário até que a condição
seja satisfeita. No caso, até a ser menor que 10.
Lógica de programação

Igualmente temos:

Repita
a = a - 1;
Escreva (a);
até que (a < 10);

Esse trecho faz o mesmo que o anterior, é apenas uma outra


estrutura de repetição. Note que o até que termina com ponto e
vírgula, pois não existe Fim Repita.

Caso não haja uma condição para o bloco parar, o código irá
se repetir eternamente podendo haver perdas consideráveis de
desempenho
Lógica de programação

Uma outra forma:

Para a de 100 até 9 faça


Escreva (a);
Fim Para

Novamente uma estrutura que diminui em 1 o valo de a até ela


ser menor que 10 (igual a 9 no caso). A diferença do Para é
que ela é uma repetição contada, ou seja, o valor de 'a' é
atribuído dentro do próprio comando (100).
Lógica de programação

Também é possível fazer:

Para a de 100 até 9 passo 2 faça


Escreva (a);
Fim Para

Nesse caso, o valor de 'a' seria diminuído em 2 a cada


repetição. Caso 'a' fosse menor que 9, o bloco não seria
executado.
Lógica de programação

Lembra deste exemplo?

faça (Subir numa cadeira/escada para alcançar o bocal);


Se (não alcançar) então
faça (procurar um objeto mais alto para subir);
Fim Se;

Por que a palavra "faça" não está destacada? Simples, porque


ela não é reservada. No exemplo acima, "faça" é uma função
separada criada por nós. Como?
Lógica de programação

Inicio Algoritmo
Inteiro Função somaInteiros (Inteiro a, Inteiro b)
Retorne a + b;
Fim Função

Inteiro x = 2;
Inteiro y = 7;
Escreva (somaInteiros (x, y) - 3);
Fim Algoritmo

Vamos analisar passo a passo...


Lógica de programação

Inteiro Função somaInteiros (Inteiro a, Inteiro b)


Retorne a + b;
Fim Função

Esse trecho cria uma função chamada 'somaInteiros' que usa


dois parâmetros de entrada: 'a' e 'b', ambos variáveis do tipo
Inteiro. Note que a mesma regra para os nomes de variáveis
também vale para nomes de funções.

Essa função devolve a soma de 'a' com 'b' através do comando


Retorne. Uma vez que a própria função é do tipo Inteiro, seu
retorno deve ser do mesmo tipo.
Lógica de programação

Inteiro x = 2;
Inteiro y = 7;
Escreva (somaInteiros (x, y) - 3);

Mais adiante, criamos duas variáveis do tipo Inteiro ('x' e 'y') e


as usamos como parâmetros para a nossa função recém
criada.

Finalmente, o resultado da função (2 + 7 = 9) é subtraido em 3,


ou seja, nosso resultado final é 6.

Vamos ver outro exemplo com a função somaInteiros...


Lógica de programação

Escreva (somaInteiros (2, 6) - 1.65);

Aqui estamos passando os números 2 e 6 para a nossa função


e subtraindo 1.65 do resultado.

Entretanto, isso não funcionaria, pois a nossa função é do tipo


Inteiro e estamos tentando subtrair um número do tipo Decimal
do retorno dela.

Quando falamos em 2, 6 e 1.65, estamos na verdade falando


de literais, ou seja, valores puros que não tem vínculo com
nenhuma variável.
Lógica de programação

Logo, o correto seria:

Inicio Algoritmo
Decimal Função somaInteiros (Decimal a, Decimal b)
Retorne a + b;
Fim Função

Escreva (somaInteiros (2.0, 6.0) - 1.65);


Fim Algoritmo
Lógica de programação

Um conceito importante a se aprender é o de vetores. Um


vetor nada mais é do que uma variável com capacidade de
armazenar vários valores diferentes, por exeplo:

Caractere Vetor a = ['a', 'b', 'c', 'd'];

Aqui criamos um vetor chamado 'a', do tipo Caractere contendo


os valores 'a', 'b', 'c' e 'd'.
Lógica de programação

Para acessar um valor dentro de um vetor, usa-se a seguinte


sintaxe:

Escreva (a[0]);

O sinal de chaves na referência da variável indica que estamos


acessando uma das posições do vetor, no caso a posição 0 (a
primeira). A maioria das linguagens de programação adota a
posição 0 como sendo a primeira posição de um vetor.
Portanto, os valores do nosso vetor e seus índices seriam:

0='a', 1='b', 2='c', 3='d'


Lógica de programação

Juntando tudo que aprendemos, já temos condições de criar


algoritmos bem complexos.

Pensemos numa calculadora. Vamos abstrair a forma que ela


funciona. Podemos usar funções para as operações básicas
(soma, subtração, multiplicação e divisão).

Também podemos criar um loop que irá se repetir enquanto o


valor informado pelo usuário no "menu" for diferente de 1, 2, 3
ou 4, sendo que cada número corresponde a uma operação.
Lógica de programação

Início Algoritmo
Decimal Função soma (Decimal a, Decimal b)
Retorne a + b;
Fim Função

Decimal Função subtrai (Decimal a, Decimal b)


Retorne a - b;
Fim Função

Decimal Função multiplica (Decimal a, Decimal b)


Retorne a * b;
Fim Função

continua...
Lógica de programação

Decimal Função divide (Decimal a, Decimal b)


Retorne a / b;
Fim Função

Decimal a = 0.0;
Decimal b = 0.0;
Inteiro opcao = 0;

Enquanto (opcao == 1 ou opcao == 2 ou opcao == 3 ou opcao


== 4) faça
Escreva ("Escolha a operação:");
Escreva ("1 - Soma");
Escreva ("2 - Subtração");
continua...
Lógica de programação

Escreva ("3 - Multiplicação");


Escreva ("4 - Divisão");

Leia (operacao);
Escreva ("Informe o primeiro número: ");
Leia (a);
Escreva ("Informe o segundo número: ");
Leia (b);

Se (operacao == 1) então
Escreva ("Resultado: ", soma (a, b));
Fim Se

continua...
Lógica de programação

Senão Se (operacao == 2) então


Escreva ("Resutado: ", subtrai (a, b));
Fim Senão Se
Senão Se (operacao == 3) então
Escreva ("Resultado: ", multiplica (a, b));
Fim Senao Se
Senão Se (operacao == 4) então
Escreva ("Resutado: ", divide (a, b));
Fim Senão Se
Fim Enquanto
Fim Algoritmo
Lógica de programação

Mas e como fica a divisão por zero? Basta alterar o trecho que
trata a operação número 4:

Senão Se (operacao == 4) então


Se (b == 0) então
Escreva ("Não é possível dividir um número por zero!");
Fim Se
Senão
Escreva ("Resutado: ", divide (a, b));
Fim Senão
Fim Senão Se
Lógica de programação

Algoritmos podem ser meio confusos a primeira vista, mas são


uma parte essencial no aprendizado da programação, portanto
não desista de tentar entendê-los!

Se você conseguiu chegar até entendendo tudo, ótimo! Você


está um passo (e muito importante) mais perto de aprender a
programar, seja em Python, Java, C++, ou o que for.

Todas as linguagens de programação tem seu funcionamento


baseado nos algoritmos, ou seja, um código-fonte nada mais é
do que um algoritmo "traduzido" para uma linguagem.
Orientação a Objetos
A Orientação a Objetos (OO) foi
criada para aproximar o mundo
real do mundo da programação.

Na OO, o desenvolvedor
"molda" um "universo" a partir
de suas abstrações.

Você lembra o que são


abstrações, não é?
Orientação a Objetos

Recapitulando: abstração é a definição de uma pessoa para


um determinado tema. Por exemplo, uma abstração para carro:

Todo carro tem: marca, modelo, cor, ano de fabricação, tipo


de combustível e chassi. (Paramos por aqui)
Todo carro: liga, desliga, acelera, freia e troca de marchas.

Pode ser que a sua definição de carro seja um pouco diferente


da minha. Isso não quer dizer necessariamente que esteja
errada.
Orientação a Objetos

Logo, se todo carro tem as características que enumeramos,


podemos considerar "Carro" como uma classe (grupo).

Uma classe é uma definição de um tipo de objeto, por


exemplo: um Ford Focus é um objeto da classe Carro, logo seu
tipo de dado é Carro.

A OO nos permite criar nossos próprios tipos de dados. Além


do Inteiro, Decimal, etc. também é possível incluir o Carro,
caso seja necessário para o nosso problema.

Carro, Pessoa, Animal, Computador... não importa! Basta criar


a classe para que ela possa ser utilizada com um tipo de dado.
Orientação a Objetos

Uma classe contém atributos e métodos. Atributos são as


características (cor, modelo, etc.), enquanto que os métodos
são as operações (ligar, trocar de marchas, etc.).

Além disso, uma classe também contém um construtor, ou


seja, um método especial (reservado) que é responsável por
inicializar a classe e seus atributos.

O construtor recebe os parâmetros necessários para a correta


instanciação (inicialização) de um objeto de uma classe
qualquer.
Orientação a Objetos

Nossa classe Carro ficaria assim:

Classe Carro
Caractere marca;
Caractere modelo;
Caractere cor;
Inteiro ano;
Caractere combustivel;
Caractere chassi;
Lógico ligado = Falso;
Orientação a Objetos

Construa Carro (Caractere mar, Caractere mod, Caractere c,


Inteiro a, Caractere com, Caractere cha)
marca = mar;
modelo = mod;
cor = c;
ano = a;
combustivel = com;
chassi = cha;
Fim Construa

Lógico Função liga ()


ligado = Verdadeiro
Fim Função
Fim Classe
Orientação a Objetos

Note que os atributos da classe são representados como


variáveis, enquanto que os métodos são representados como
funções. Note que o construtor também é uma função e que
criei apenas a função 'liga' no exemplo para não ficar muito
grande.

Notou que as variáveis foram declaradas sem um valor


atribuído a elas? Isso foi feito porque a tarefa de dar um valor
às variáveis é trabalho do construtor.

No momento em que criamos um objeto da classe Carro, o


construtor é executado. Logo, devemos criar nosso objeto
passando os valores que queremos e o construtor irá atribuir
esses valores às variáveis correspondentes.
Orientação a Objetos

Isso acontece da seguinte maneira:

Carro fordFocus = Carro ('Ford', 'Focus', 'azul', 2007, 'gasolina',


'879876567');

Quando esse trecho é executado, o construtor da classe Carro


é disparado atribuindo os valores que passamos e então nosso
objeto é criado e armazenado a variável 'fordFocus', do tipo
Carro.
Orientação a Objetos

O que acontece se quisermos alterar a cor do nosso objeto


'fordFocus'? Simplesmente podemos acessar a variável 'cor' e
redefinir seu valor. Isso é feito através de um sinal de ponto:

fordFocus.cor = 'vermelho';

O mesmo vale para as outras variáveis. O símbolo do ponto diz


que a variável cor que queremos mudar é do nosso
'fordFocus'.

Basicamente, o ponto nos dá acesso aos atributos e métodos


de uma classe.
Orientação a Objetos

Lembre-se que a variável 'ligado' é inicializada como Falso. Se


quisermos ligar o carro, podemos tanto alterar diretamente o
valor da propriedade 'ligado', quando utilizar a função 'liga':

fordFocus.ligado = Verdadeiro;
fordFocus.liga();
Orientação a Objetos

A OO nos dá ferramentas para organizar melhor nosso


trabalho, de forma que um erro acontecer em alguma parte do
algoritmo, fica fácil de corrigí-lo, bastando alterar apenas
aquela parte específica em vez do algoritmo todo.

O Python é uma linguagem orientada a objetos, assim como os


módulos da BGE estão também foram desenvolvidos usando a
OO, portanto é bom que entenda bem os conceitos antes de
continuar.

Ainda há muito mais para se aprender sobre algoritmos e OO,


porém vou deixar isso a seu critério. Se você entendeu tudo
até aqui, então está já pronto para o Python.
Python
Agora as coisas começam a ficar
interessantes! Recomendo que tenha
entendido bem a parte de algoritmos antes
de continuar. Embora não seja obrigatório,
irá facilitar muito a sua vida.

Python é uma linguagem de programação


de alto nível, ou seja, é bem próxima a
linguagem natural (humana). Portanto,
escrever um código em Python é quase a
mesma coisa que escrever um algoritmo.
As diferenças são muito poucas.
Python

Python também é uma linguagem interpretada, ou seja, para


rodar um programa em Python, é necessário ter o interpretador
do Python instalado no sistema ou embutido em sua aplicação.

Uma coisa importante a esclarecer é que Python não gera


executáveis (.exe) nativamente. Isso se dá pelo fato de que ele
é uma linguagem de scripts. Existem formas de se gerar
executáveis, mas esse assunto não será abordado neste
curso.
Python

Antes de continuar, preciso que você instale o Python em seu


sistema. Ele pode ser baixado aqui: http://www.python.org/

Se tudo deu certo, se você for ao menu Iniciar - Executar,


digitar "python" e clicar em ok deverá ver esta janela:
Python

Caso tenha recebido alguma mensagem de erro, clique com o


botão direito do mouse em “Meu computador”, e depois em
“propriedades”. Clique na guia “avançado” e clique em
“variáveis de ambiente”. Na janela “Variáveis de sistema”
escolha a variável "path" e clique em "editar". Agora
acrescente o endereço do interpretador nesta variável
antecedido por um ponto e virgula “;”.
Python
Muito bem, com tudo pronto podemos começar a brincar com o
interpretador. As frases depois do caractere "#" são
comentários, ou seja, não farão nada no código.Tente os
seguintes comandos (tecle Enter no final de cada um):

2+2 #Aqui o retorno é 4


2 == 2 #Aqui o retorno é True (Verdadeiro)
2 != 2 #Aqui o retorno é False (Falso)
a=2 #Sem retorno
a #Aqui o retorno é 2
a+2 #Aqui o retorno é 4
a #Aqui o retorno é 2 (a não foi somado)
a = a + 2 #Sem retorno (a foi somado)
a #Aqui o retorno é 4
a += 2 #Sem retorno (equivale a: a = a + 2)
a #Aqui o retorno é 6
Python

Como você pode ver, conforme vamos digitando os comandos,


vamos obtendo as respostas logo em seguida. Notou que o
Python não usa pronto e vírgula no fim das instruções? Você
deve ter notado também que o modo de trabalhar com
variáveis é um pouco diferente do que aprendemos nos
algoritmos.

Não precisamos informar o tipo da variável antes da sua


declaração (nome), pois a linguagem se encarrega de
descobrir o tipo automaticamente para nós baseando-se no
valor atribuído à variável. Isso é chamado de tipagem
dinâmica.
Python

Com o conceito de tipagem em mente, deve-se saber que as


variáveis podem ter seu tipo alterado ao decorrer do código,
por exemplo:

a=2 #Sem retorno


a #Retorno: 2
a = 2.4 #Sem retorno
a #Retorno: 2.4
a = 'bla bla bla' #Sem retorno
a #Retorno: 'bla bla bla'

Portanto, bastante atenção na hora de usar as variáveis. Não


tente fazer algo como 'a +2', se 'a' estiver com o valor 'bla bla
bla' ou você verá uma bela mensagem de erro.
Python

Também é possível converter variáves:

a = '3' #definimos a como um Caractere ('3')


a = int (a) #redefinimos a convertendo-o para Inteiro
a = str(a) #convertemos novamente para Caractere

Os tipos de dados suportados pelo Python que mais iremos


utilizar são: 'int' (Inteiro), 'float' (Decimal), 'long' (Inteiro longo),
'str' (Caractere) e 'list' (lista).

Existe o Inteiro longo, pois o 'int' só suporta um determinado


número de dígitos, logo se você tiver um número muito grande,
ele deve ser do tipo 'long'.
Python

Já a lista, é o próprio Vetor, porém ela contém métodos para


que se possa, entre outras coisa, adicionar, remover, dividir e
ordenar os dados contidos nela. Por exemplo:

lista = ['a', 'g'] #criamos um Vetor de caracteres


lista.append ('f') #adicionamos o 'f' ao fim do vetor
lista.sort () #ordenamos o vetor ['a', 'f', 'g']
lista.remove ('a') #removemos o 'a' do vetor

Portanto, daqui pra frente quando falarmos em vetores,


estaremos falando de algoritmos e quando falarmos em listas,
estaremos falando de Python.
Python
O modo como o Python trata as condições é a seguinte:

if a > 10: #if é o Se dos algoritmos


print a, ' é maior que 10' #print é o Escreva
elif a < 10 : #elif é o Senao Se
print a, ' é menor que 10'
else: #else é o Senao
print a, ' é igual a 10'

Mais algumas diferenças a observar:


'elif' é a abreviação de 'else if' (Senão Se)
'print' não imprime algo na impressora, mas sim na tela. É o
mesmo que o Escreva nos algoritmos
Nem o 'if' (e variantes), nem o 'print' precisam de
parênteses (Porém Python 3.0 e superiores precisam de
parenteses)
Python

É possível escrever várias linhas com um único print usando-


se três aspas no começo e no fim da instrução:

print """Primeira linha


Segunda linha
Terceira linha"""

Também é possível usar os caracteres \n para quebra de linha:


print """Primeira linha\n Segunda linha\n Terceira linha"""
Python

Outra coisa importante a se notar é que os blocos não


possuem uma demarcação de Inicio e Fim como nos
algoritmos. Ao invés disso, o Python usa um sinal de dois
pontos para demarcar o início de um bloco. Todo o código
dentro dele deve estar com uma tabulação (4 espaços) a mais
que a linha inicial.

O Python entende que um bloco termina, quando a tabulação


diminui, ou seja, quando é igual ao da primeira linha.

if a > 10: #dois pontos = Inicio


print a, 'é maior que 10' #+1 tabulação = bloco
else: #-1 tabulação = Fim
print a, 'não é maior que 10'
Python

Para fazer um Leia em Python, usa-se a função 'raw_input':

a = raw_input() #Ficará esperando uma entrada no teclado


print a #Mostrará o valor passado para 'a'

O Python diferencia funções de variáveis pelos parênteses.


Como raw_input é uma função, temos que colocar os sinais de
abre e fecha parênteses.

Não há nada dentro dos parênteses porque não informamos


nenhum parâmetro à função.
Python

Eis um exemplo de função com parâmetros:

def soma (a, b): #define-se a função 'soma'


return a + b #seu retorno é a soma dos parametros

soma (2, 3) #usa-se a função para somar 2 e 3

A palavra 'def' é a abreviação de 'define' (defina), ou Função,


no caso dos algoritmos. Novamente não é preciso informar o
tipo de dados, pois ele é definido automaticamente através do
comando 'return' (Retorne).
Python

Os operadores do Python são os mesmos utilizados nos


algoritmos. Recapitulando:

Atribuição (a = 10): atribui um valor a uma variável


Igualdade (a == 10): compara se dois valores são iguais
Maior (a > 10): compara se um valor é maior que outro
Menor (a < 10): compara se um valor é menor que outro
Maior ou igual (a >= 10): compara se um valor é maior ou
igual a outro
Menor ou igual (a <= 10): compara se um valor é menor ou
igual a outro
Diferença (a != 10): compara se um valor é diferente do
outro.
Python

A estrutura Enquanto/faça dos algoritmos em Python é a


seguinte:

a = 10 #criamos a variavel 'a' com valor 10

while a != 0: #enquanto 'a' for diferente de zero


a -= 1 #diminui-se um do valor de 'a'
print a #mostra o valor na tela

A diferença aqui é que o 'while' (Enquanto) não precisa de um


faça. Como as demais estruturas, ela também não requer
parênteses.
Python

A estrutura Repita/até que não existe em Python. Uma vez que


é idêntica ao Enquanto/faça. Entretanto, a estrutura Para/faça
existe, uma vez que seu funcionamento é diferente do
Repita/até que:

for i in range (1, 10):


print i

Aqui temos um 'for' (Para) que está trabalhando em cima de


uma variável 'i' num intervalo de 1 a 10 (função 'range'). A cada
repetição, o valor da variável é mostrado na tela.
Python

A função 'range' cria um intervalo completo de valores, ou seja,


um Vetor. No caso do exemplo: [1, 2, 3, 4, 5, 6, 7, 8, 9]

Porque vai até 9 e não até 10? Porque a função range tem seu
primeiro parâmetro inclusivo e o segundo exclusivo, ou seja, o
valor informado no primeiro parâmetro é incluído no vetor e o
segundo não.

Se a idéia era criar uma lista de 10 posições, então


poderíamos usar simplesmente:

range (10)
Python

O funcionamento da esturura 'for' é basicamente a seguinte:

É necessária uma variável (no exemplo, 'i')


É necessário um intervalo de valores para determinar o
número de repetições.
A palavra 'in' é uma estrutura condicional, ou seja, retorna
Verdadeiro (True) ou Falso (False)
Logo, o 'for' testa a cada repetição se o valor da variável
está dentro do intervalo definido. Se estiver, o retorno é
verdadeiro, 'i' recebe o valor da posição atual da lista e a
repetição continua
Caso seja falso, a repetição acaba
Python

Você pode testar a condição 'in':

vetor = [1, 5, 7, 6]#vetores também não precisam de tipo


a=2
a in vetor #testa se 'a' está dentro do vetor
a=5
a in vetor

Também é possível usar o 'in' dentro de um 'if', por exemplo:

if a in vetor:
print a, ' está dentro do vetor'
Python

Lembra do algoritmo da nossa calculadora? Hora de dar vida a


ela. Crie um arquivo chamado "calculadora.py" e escreva o
seguinte:

def soma (a, b):


return a + b

def subtrai (a, b):


return a - b

def multiplica (a, b):


return a * b;

def divide (a, b):


return a / b;
continu
a...
Python

a = 0.0
b = 0.0
operacao = 1

while (operacao in [1, 2, 3, 4]):


print """Escolha uma operacao:'
1 - Soma'
2 - Subtracao'
3 - Multiplicacao'
4 - Divisao"""
operacao = int (raw_input())

print 'Informe o primeiro numero: '


a = float (raw_input())
print 'Informe o segundo numero: '
b = float (raw_input())
continua...
Python

if operacao == 1:
print 'Resultado: ', soma (a, b)
elif operacao == 2:
print 'Resultado: ', subtrai (a, b)
elif operacao == 3:
print 'Resultado: ', multiplica (a, b)
elif operacao == 4:
if b == 0:
print 'Não é possível dividir um número por zero'
else :
print 'Resultado: ', divide (a, b)

Execute esse script dando um clique duplo em cima dele. Caso


não consiga, associe o Python como programa padrão para
arquivos .py
Python

Aqui um exemplo de uma classe em Python:

class Humano:
nome = None
idade = None
sexo = None
altura = None
peso = None

def __init__(self, novoNome, novaIdade, novoSexo, novaAltura, novoPeso):


self.nome = novoNome
self.idade = novaIdade
self.sexo = novoSexo
self.altura = novaAltura
self.peso = novoPeso
continua...
Python

def mostraDados(self):
print 'Nome: ' + self.nome
print 'Idade: ' + str(self.idade)
print 'Sexo: ' + self.sexo
print 'Altura: ' + str(self.altura)
print 'Peso: ' + str(self.peso)

humano1 = Humano('Fulano', 32, 'M', 1.82, 68)


humano2 = Humano('Ciclana', 22, 'F', 1.67, 58)

humano1.mostraDados()
humano2.mostraDados()
Python

Partindo do princípio, temos a criação da classe ('class') e seus


atributos:

class Humano:
nome = None
idade = None
sexo = None
altura = None
peso = None

O termo 'None' (necessário letra maiúscula) se refere a um


valor em branco, ou seja, nossas variáveis não tem valor
algum atribuído a elas.
Python

Em seguida temos o construtor:

def __init__(self, novoNome, novaIdade, novoSexo, novaAltura, novoPeso):


self.nome = novoNome
self.idade = novaIdade
self.sexo = novoSexo
self.altura = novaAltura
self.peso = novoPeso

Como o construtor é uma função, deve-se usar o 'def'. O termo


'__init__' (abreviação de initialize, ou inicialize) é o termo
reservado no Python para construtores.
Python

O termo 'self', refere-se à própria classe, ou seja, se nosso


construtor fosse assim ele nao iria funcionar:

def __init__(self, nome, idade, sexo, altura, peso):


nome = nome
idade = idade
sexo = sexo
altura = altura
peso = peso
Python

O que aconteceria é que as variáveis da classe não


receberiam valor algum! A instrução abaixo iria apenas
substituir o valor da variável nome com o próprio valor que já
está atribuído a ela:

nome = nome

Para entender isso, precisamos entender o conceito de


variável local e global.
Python

Uma variável local é aquela que só é acessível dentro do


próprio bloco onde ela se encontra, enquanto que uma variável
local é acessível de qualquer lugar do código (após sua
criação). Um exemplo:

nome = 'Meu nome'

def trocaNome (novoNome):


nome = novoNome

print novoNome
print nome

Aqui teríamos um erro, pois estaríamos tentando acessar uma


variável que não existe mais.
Python

A fim de economizar memória e processamento, assim que


uma função termina de ser executada, as variáveis locais dela
são apagadas.

Por isso não conseguimos mostrar o valor da variável


'novoNome' fora da função 'trocaNome'. Entretanto, o valor da
variável 'nome' é mostrado pois ela ainda existe.

Uma regra simples para variáveis locais é: variáveis somente


são acessíveis enquanto a identação for a mesma. Ou seja, se
uma instrução com identação menor tentar acessar uma
variável que está com identação maior, irá ocorrer um erro.
Python

A regra para variáveis globais é: variáveis com identação


menor são acessíveis para instruções com identação maior.

Portanto, como no exemplo da classe Humano temos duas


variáveis com o mesmo nome, devemos dizer ao construtor
que o valor que queremos atribuir é para a variável 'nome' da
classe, e não o parâmetro 'nome'. Isso é feito usando a palavra
'self' (si próprio).

def __init__(self, nome, idade, sexo, altura, peso):


self.nome = nome
Python

Note também que existe uma palavra 'self' como primeiro


parâmetro do construtor. Isso é uma regra do Python que diz
que toda função dentro de uma classe deve começar com a
palavra 'self', incluindo o construtor. Por isso, o método
'mostraDados' da classe também tem esse parâmetro:

def mostraDados(self):
print 'Nome: ' + self.nome
print 'Idade: ' + str(self.idade)
print 'Sexo: ' + self.sexo
print 'Altura: ' + str(self.altura)
print 'Peso: ' + str(self.peso)
Python

Ao final do exemplo, criamos dois objetos da classe Humano e


chamamos a função 'mostraDados' de cada um.

humano1 = Humano('Fulano', 32, 'M', 1.82, 68)


humano2 = Humano('Ciclana', 22, 'F', 1.67, 58)

humano1.mostraDados()
humano2.mostraDados()

Tente executar esse exemplo (usando o código completo) para


ver como ele funciona e qual é o retorno final.
Python

Tente executar esse trecho de código no interpretador do


Python (linha de comando):

import datetime
print datetime.datetime.now()

Seu retorno deve ser o dia e a hora atuais. O comando 'import'


diz ao Python para carregar um módulo. Somente depois que
um módulo é carregado é que podemos utilizá-lo.

O módulo 'datetime' é responsável por funções de hora e data


no Python.
Python

Um módulo, nada mais é do que uma pasta de arquivos


contendo um arquivo chamado "__init__.py" dentro dela. Como
você deve lembrar a palavra '__init__' é usada para inicializar
classes, mas também serve para dizer ao Python que uma
pasta é um módulo.

Como você deve imaginar, esse arquivo também é


responsável por inicializar o módulo. Além dele, a pasta
também deve conter pelo menos um outro arquivo com
extensão ".py" qualquer.

Esse arquivo é o módulo em si, ou seja, deve conter variáveis,


funções, classes, etc. a fim de realizar uma tarefa.
Python

Você pode criar um módulo chamado "minhasFuncoes". Para


isso, basta criar uma pasta com esse mesmo nome, dentro
dela criar um arquivo chamado "__init__.py".

Dentro desse arquivo, coloque apenas:

from minhasFuncoes import *

Isso diz ao Python para importar tudo ('*') de dentro ('from') do


arquivo 'minhasFuncoes'. Ainda dentro da pasta crie o arquivo
"minhasFuncoes.py".
Python

Dentro do novo arquivo, coloque isso:

def funcao1():
print 'Primeira funcao'

def funcao2():
print 'Segunda funcao'

Fora da pasta minhasFuncoes, crie um arquivo com qualquer


nome, como "teste.py", por exemplo. Dentro dele coloque:

import minhasFuncoes

minhasFuncoes.funcao1()
raw_input()
Python

Ao executar o arquivo "teste.py", devemos receber a


mensagem "Primeira funcao" como saída. Como o Python
fecha a tela do console assim que a execução termina,
colocamos um 'raw_input' no fim do arquivo para que o
interpretador fique esperando uma entrada no teclado. Isso nos
dá tempo de ver a mensagem.

O que fizemos foi importar o módulo 'minhasFuncoes' e


chamar a função 'funcao1' desse módulo. Note que módulos
também podem ser locais e globais e o que fizemos foi criar
um módulo local.
Python

Se você executar o console do Pyhton e tentar importar seu


módulo recém criado, deverá receber uma mensagem de erro.
Python

Isso acontece porque nosso módulo não é global. Para torná-lo


global, precisamos colocá-lo na pasta "Lib" que se econtra
dentro da pasta de instalação do Python.

Depois de fazer isso, podemos executar o interpretador


novamente e tentar fazer a importação. Nesse caso, não
iremos receber mensagem de erro, o que significa que o
módulo foi importado corretamente.
Python
Python

Ao fazer importações, é possível dar um "apelido" (alias) aos


módulos, como por exemplo:

import datetime as dt
print dt.datetime.now()

Nesse caso, importamos o módulo 'datetime' como 'dt'.


Quando usamos o apelido, o Python sabe que estamos na
verdade falando do módulo.
Python

Para finalizar, devo lhe apresentar um conceito muito útil:

def igualADez (numero):


if numero == 10:
return True
return False

numero = 5
resultado = igualADez (numero)
if (resultado):
print numero, ' é igual a 10'
else:
print numero, ' é diferente de 10'
Python

No exemplo criamos uma função que testa se um número é


igual a 10 e retorna Verdadeiro ou Falso. Na primeira linha da
função, temos a comparação do número com 10. Se for
verdadeira, a função irá retornar 'True'.

É importante dizer que assim que o 'return' é executado, a


função termina, pois já se tem um resultado. Portanto a função
só irá retornar 'False' quando a condição não for verdadeira.
Python

Em seguida, temos a criação da variável global 'numero'


(diferente do parâmetro 'numero') e lhe atribuímos o valor 5.

Em seguida criamos a variável 'resultado' que recebe o retorno


da função 'igualADez' e lhe passa a variável 'numero' como
parâmetro. Logo, o valor da variável 'resultado' nesse caso
seria 'False' e ela seria do tipo boolean (Lógico).
Python

No final do código temos uma condição meio estranha. Como


assim "if resultado"?

Como você deve lembrar, o bloco 'if' só é executado se sua


condição for verdadeira. Isso pode ser conseguido tanto com
uma comparação (a maior que b, por exemplo) como usando
diretamente um valor Verdadeiro (True).

No exemplo, o valor de 'resultado' é False, portanto o bloco


'else' será executado.
Python

Uma outra forma de fazer a mesma coisa e economizar


algumas linhas seria:

if (igualADez(5)):
print '5 é igual a 10'
else:
print '5 é diferente de 10'

Como a função 'igualADez' retorna apenas True ou False, é


tudo que precisamos para poder usá-la como parâmetro no
nosso 'if'.
Python

Eis uma agenda simples:

#-*- coding: utf-8 -*-


class Contato:
codigo = None
nome = None
telefone = None

def __init__(self, novoCodigo, novoNome, novoTelefone):


self.codigo = novoCodigo
self.nome = novoNome
self.telefone = novoTelefone

continua...
Python

contatos = []
op = 0

while op != 5:
print u'Escolha uma opção:'
print '1- Visualizar contatos'
print '2- Adicionar contato'
print '3- Editar contato'
print '4- Remover contato'
print '5- Sair'

try:
op = int(raw_input())
except:
print u'Esolha uma opção de 1 a 5'
raw_input()

continua...
Python

if op == 1:
for contato in contatos:
print u'Código: ', contato.codigo
print 'Nome: ', contato.nome
print 'Telefone: ', contato.telefone
print '\n'
elif op == 2:
print u'Código: '
codigo = raw_input()
for contato in contatos:
if contato.codigo == codigo:
print u'Esse código já existe'
break
print 'Nome: '
nome = raw_input()
print 'Telefone: '
telefone = raw_input()
contatos.append(Contato(codigo, nome, telefone))

continua...
Python

elif op == 3:
print u'Código: '
codigo = raw_input()
for contato in contatos:
if contato.codigo == codigo:
print u'Novo código: '
contato.codigo = raw_input()
print 'Novo nome: '
contato.nome = raw_input()
print 'Novo telefone: '
contato.telefone = raw_input()
break

continua...
Python

elif op == 4:
print u'Código: '
codigo = raw_input()
for contato in contatos:
if contato.codigo == codigo:
contatos.remove(contato)
print 'Contato removido!'
break

Esse código deve ser capaz de mostrar os contatos (código,


nome e telefone), adicionar um novo contato, editar um contato
existente e remover um contato.

Vamos analisá-lo por partes


Python

#-*- coding: utf-8 -*-


class Contato:
codigo = None
nome = None
telefone = None

def __init__(self, novoCodigo, novoNome, novoTelefone):


self.codigo = novoCodigo
self.nome = novoNome
self.telefone = novoTelefone

Nenhuma surpresa aqui, exceto pela primeira linha. Ela nos diz
que a codificação do nosso arquivo .py é UTF-8, ou seja, que
queremos ser capazes de mostrar acentos e outros caracteres
especiais nas nossas mensagens.
Python

Para que isso funcione, é preciso configurar nosso editor para


trabalhar com UTF-8. No caso do Notepad++ (o que eu
recomendo), isso pode ser feito no menu Formatar -
Codificação UTF-8.
Python

contatos = []
op = 0

while op != 5:
print u'Escolha uma opção:'
print '1- Visualizar contatos'
print '2- Adicionar contato'
print '3- Editar contato'
print '4- Remover contato'
print '5- Sair'

try:
op = int(raw_input())
except:
print u'Esolha uma opção de 1 a 5'
raw_input()

Aqui criamos uma lista vazia onde serão guardados os


contatos. Também mostramos as opções e a lemos.
Python

try:
op = int(raw_input())
except:
print u'Esolha uma opção de 1 a 5'
raw_input()

Usamos o 'try' (tente) quando alguma parte do nosso código


pode gerar algum erro e o programa ser simplesmente
finalizado por isso.

O 'except' (exceto) é o que deve ser executado caso o 'try'


falhe. Se digitássemos letras ao invés de números, isso faria o
casting (conversão para inteiro do 'raw_input') dar erro e então
o 'except' seria executado
Python

if op == 1:
for contato in contatos:
print u'Código: ', contato.codigo
print 'Nome: ', contato.nome
print 'Telefone: ', contato.telefone
print '\n'

Aqui tratamos da opção número 1 (visualizar contatos)


selecionando cada item (contato) dentro da lista (contatos) e
mostrando seu respectivo código, nome e telefone.

O 'u' antes de uma string, significa que ela deve ser convertida
para Unicode. Assim os caracteres especiais e de acentuação
aparecem corretamente. O '\n' é um caractere especial que
serve para pular uma linha.
Python

elif op == 2:
print u'Código: '
codigo = raw_input()
for contato in contatos:
if contato.codigo == codigo:
print u'Esse código já existe'
break
print 'Nome: '
nome = raw_input()
print 'Telefone: '
telefone = raw_input()
contatos.append(Contato(codigo, nome, telefone))

A opção 2 não muda muito. Aqui lemos um código, buscamos


na lista para ver se ele já existe e então gravamos os novos
dados na lista. O comando 'break' serve para interromper a
repetição de um laço ('while', 'for').
Python

elif op == 3:
print u'Código: '
codigo = raw_input()
for contato in contatos:
if contato.codigo == codigo:
print u'Novo código: '
contato.codigo = raw_input()
print 'Novo nome: '
contato.nome = raw_input()
print 'Novo telefone: '
contato.telefone = raw_input()
break

Aqui procuramos o contato com o código informado e, assim


que o acharmos, gravamos os novos dados por cima dos
antigos e interrompemos a repetição ('break').
Python

elif op == 4:
print u'Código: '
codigo = raw_input()
for contato in contatos:
if contato.codigo == codigo:
contatos.remove(contato)
print 'Contato removido!'
break

Aqui buscamos na lista pelo contato com o código informado, o


removemos dela e interrompemos a repetição.

Quanto interrompemos a repetição, o 'break' nos leva para fora


do bloco.
Python

Muito bem, mas esse tipo de informação é valiosa e acredito


que você não gostaria de perder seus dados assim que o
programa for fechado não é?

É necessário um jeito de fazer com que os dados fiquem


gravados mesmo que o programa seja fechado e o computador
seja desligado.

Podemos fazer isso com arquivos ou com banco de dados e


irei mostrar os dois jeitos. Teremos um capítulo todo sobre
banco de dados mais adiante, então vamos nos concentrar na
idéia dos arquivos.
Python

O Python tem a função 'open', que retorna um objeto do tipo


File (arquivo). Esse objeto possui funções para ler arquivos,
bem como gravar dados dentro deles.

A primeira mudança que faremos no nosso código da agenda é a


a variável 'CAMINHOARQUIVO' ao início do código:

#-*- coding: utf-8 -*-


import os
CAMINHOARQUIVO = os.path.dirname(os.path.abspath(__file__)) + '\\agenda.txt'
Python

Para que o código funcione, é necessário criar o arquivo


"agenda.txt" na mesma pasta em que se encontra o arquivo
"agenda.py".
Python

O que fizemos foi importar o módulo 'os' (Operating System)


que possui funções específicas para cada sistema operacional.

Depois disso, criamos uma variável ('CAMINHOARQUIVO')


que basicamente pega o caminho completo do arquivo
"agenda.py".

Com o caminho em mãos, adicionamos mais uma barra e o


nome do nosso arquivo. É necessário usar duas barras, pois a
barra identifica um caractere específico (lembra do '\n'?), logo
quando escrevemos '\\' o retorno será apenas uma barra.
Python

Agora vamos precisar ler o conteúdo do arquivo e convertê-lo


em objetos da nossa classe Contato. Entretando, não temos
como fazer isso porque o arquivo "agenda.txt" está vazio.

Outra coisa que nos impede é que ainda não criamos um


padrão de formatação para o arquivo, então vamos estabelecer
assim:

[codigo]1[nome]Fulano de Tal[telefone](44) 4444-4444

O que estiver depois do símbolo de fechamento de chave (']') é


o que queremos.
Python

Portanto, vamos inserir alguns contatos nesse formato no


nosso arquivo "agenda.txt":

Não se esqueça de salvar esse arquivo no formato UTF-8


tambem!
Python

Agora que temos nosso padrão e alguns dados, vamos


adicionar a função que lê os dados do arquivo:
contatos = []
op = 0

for linha in open (CAMINHOARQUIVO):


split = linha.split(']')
novoContato = Contato(None, None, None)

for item in split:


novoItem = item.replace('[codigo', '').replace('[nome', '')
novoItem = novoItem.replace('[telefone', '').replace('\n', '')
novoItem = novoItem.replace('\xef\xbb\xbf', '')
if split.index(item) == 1:
novoContato.codigo = novoItem
elif split.index(item) == 2:
novoContato.nome = novoItem
elif split.index(item) == 3:
novoContato.telefone = novoItem
contatos.append(novoContato)
Python

Uma porção de coisas novas para nós:

a função 'open' retorna um arquivo. Quando executamos


uma operação de iteração sobre ele, o que é retornado são
suas linhas no formato de lista.
A função 'split' separa uma string em pedaços. Esses
pedaços são configurados de acordo com outra string, no
caso do exemplo, "cortamos" a string nos símbolos de
fechamento de chaves. Assim temos uma lista de strings
sem esse caractere.
Python

A função 'replace' substitui pedaços de string por outros, no


exemplo, substituímos as partes que não queríamos (como
"[codigo") por um caractere vazio (''), o que remove da
string o que não nos serve.
A função 'index' retorna o índice de um elemento dentro de
uma lista (vetor). Sabendo que o índice do código é 1, do
nome é 2 e do telefone é 3, pudemos ver se o item atual
era um desses e definir o valor à variável correspondente.
A função 'append' adiciona um elemento ao final de uma
lista, como você deve se lembrar
Python

Com isso, já podemos executar o programa e selecionar a


opção para visualizar os contatos. Eles devem aparecer
perfeitamente na tela.

Entretanto, ainda é necessário gravar os contatos no arquivo


antes de fechar o programa. Para isso, adicione o seguinte ao
fim do código todo:

arquivo = open(CAMINHOARQUIVO, 'w')


for contato in contatos:
linha = '[codigo]' + contato.codigo + '[nome]' + contato.nome + '[telefone]' + contato.telefone + '\n'
arquivo.write(linha)
Python

Aqui simplesmente abrimos o arquivo no modo de escrita ('w'),


o que significa que todo o seu conteúdo será apagado quando
ele for aberto. Como já havíamos carregado os dados antes,
isso não nos preocupa e é até melhor para evitar duplicidade.

Depois, para cara contato da nossa lista, criamos uma string


dentro do nosso padrão (com o '\n' no final) e a gravamos no
arquivo.

Como você pode notar, dá um certo trabalho gravar dados em


arquivos e essa é uma prática que eu não recomendo (a
menos que seja necessário). É muito mais simples e seguro
usar um banco de dados para isso.
Python

Não é tão difícil programar em Python. É necessário apenas


algum tempo conhecendo a sintaxe da linguagem e algum
conhecimento em Inglês ajuda nessa tarefa.

A parte mais difícil do processo todo é aprender a abstrair os


objetos do mundo real e executar processos através de Lógica
de Programação com eles.

Portanto, caso não tenha entendido bem alguma coisa, releia


quantas vezes forem necessárias até conseguir.

Existe muito mais sobre Python a se falar, mas para o nosso


curso, isso deve ser o suficiente.
Banco de dados

Armazenar dados em arquivos não é


uma tarefa das mais fáceis e
confiáveis, pois somos nós que
temos que implementar toda a lógica
dessa idéia.

Usar um banco de dados é a melhor


alternativa para se armazenar
dados, seja de um programa, jogo,
ou o que for.
Banco de dados

Você se lembra como se parece uma planilha eletrônica


(Excel, Calc, etc)? Temos uma tabela com linhas e colunas,
certo?

Geralmente, na primeira linha colocamos o nome dos campos,


e nas linhas seguintes os dados. Logo, cada coluna representa
uma informação diferente, a primeira linha representa a
descrição dessa informação e as linhas seguintes representam
os dados.

Um banco de dados funciona de forma parecida, exceto que


ele nos dá ferramentas para controlar melhor e mais facilmente
nossos dados.
Banco de dados

Nossa primeira ferramenta de aprendizado será o Base do


BrOffice. Recomendo que baixe-o: http://www.broffice.org

Você também pode usar o Microsoft Access se quiser, mas as


instruções deste curso serão direcionadas ao Base.

Uma vez instalado, abra-o e vamos começar!


Banco de dados

Ao abrir o Base, um assistente será mostrado. Nele, escolha


"Criar novo banco de dados" e clique em "Próximo".
Banco de dados

Na tela seguinte, marque "Sim, registre o banco de dados para


mim" e "Abrir o banco de dados para "Edição". Clique em
"Concluir" e salve-o em algum lugar.
Banco de dados

A seguir, no menu de tarefas, clique em "Criar tabela no


editor".
Banco de dados

Crie os campos como mostrado abaixo:

Nada muito complicado, temos um campo (coluna) para o


código (tipo numérico), um para o nome (tipo texto) e um para
o telefone (tipo texto). Colocamos também uma descrição para
cada um.
Banco de dados

Clique com o botão direito do mouse sobre o pequeno


quadrado antes do campo "codigo" (onde está a seta verde na
imagem) e marque "Chave primária":

Uma chave primária é o que identifica um registro (linha) numa


tabela. Em resumo, ele é o código daquele registro. Uma
chave primária é única, ou seja, não podem haver dois
registros com a mesma chave (código).
Banco de dados

Clique no botão "Salvar" e salve a tabela com o nome


"Contato":

Em seguida, feche o editor de tabelas.


Banco de dados

No menu de tabelas, clique duas vezes na tabela "Contato"


para abrir o editor de dados:

No editor de dados, crie alguns registros dando um código


único a cada um, salve e feche o editor de registros:
Banco de dados

Vamos parar para analisar a teoria por trás do que fizemos (ou
melhor, o Base fez para nós).

Como já foi dito, uma tabela funciona de forma parecida com


uma planilha (Excel, Calc), sendo que em cada coluna é
colocado um campo diferente (nome, telefone,...) e em cada
linha é colocado um registro diferente.

Cada registro é identificado pela chave primária, que é uma


espécie de código. A chave primária deve ser única para cada
registro na tabela. Caso você tente inserir um registro com uma
chave primária que já existe receberá um erro.
Banco de dados

A forma como se define uma tabela não difere muito da forma


como se define uma classe em algoritmos, sendo que cada
atributo (campo) deve ter um nome e um tipo de dados.

Ao inserir um novo registro numa tabela, uma nova linha é


criada e ela se parece cada vez mais com uma planilha
eletrônica.

O Base nos dá ferramentas simples para criar tabelas e inserir


registros dentro delas, mas por trás dos panos, o que ele faz
mesmo é executar comandos SQL.
Banco de dados

SQL (Structed Query Language) é a linguagem que os bancos


de dados entendem e com ela é possível criar tabelas, inserir
registros, consultar registros, remover tabelas e registros, etc.

Para começar, vamos aprender o comando SQL para consultar


registros dentro de uma tabela. Ele é composto por três partes:

O que deve ser selecionado


De onde deve ser selecionado
Como deve ser selecionado
Banco de dados

Portanto, se quisermos selecionar todos registros da tabela


Contato, faríamos assim:

SELECT *
FROM Contato

Aqui selecionamos ('SELECT') todos os campos ('*') da tabela


Contato ('FROM Contato'). Como você já sabe, a consulta é
dividida em três partes, mas a última (como deve ser
selecionado) não é obrigatória.
Banco de dados

Vá até o Base e clique no botão "Consultas", depois em "Criar


consulta no editor de SQL":

Na nova tela que se abre, coloque o comando do slide anterior


e tecle F5 para executá-lo.
Banco de dados

Como resultado temos todos os registros da tabela Contato:


Banco de dados

Vamos ser um pouco mais específicos agora e selecionar


apenas o registro com código 2:

SELECT *
FROM Contato
WHERE codigo = 2

O comando WHERE (onde) é a terceira parte da consulta, ou


seja, como deve ser consultado. Em outras palavras, o
WHERE é a condição.
Banco de dados

E aí está o resultado da nossa consulta mostrando apenas o


registro com código igual a 2:
Banco de dados

Também é possível filtar os valores por faixas, como no


exemplo:

Aqui filtramos o resultado para mostrar apenas os que tem o


código igual a um dos elementos dentro ('IN') da lista.
Banco de dados

Também é possível filtrar textos:

Aqui filtramos a consulta para mostrar apenas os registros que


tem o campo nome com valor exatamente igual a 'Fulano de
Tal'.
Banco de dados

Se quiséssemos saber os nomes que terminam com 'de Tal',


faríamos assim:

SELECT *
FROM Contato
WHERE nome LIKE '%de Tal'

O comando LIKE (parecido, próximo) nos permite filtrar textos


de forma a termos mais controle sobre o que será mostrado.

O símbolo '%' quer dizer que não importa o que venha antes
de 'de Tal'. Contanto que o registro termine assim, ele deve ser
mostrado.
Banco de dados

O '%' é um caractere coringa na filtragem de strings pelo


comando LIKE. Além dele, também pode ser usado o '_'.
Vejamos a diferença entre eles:

%: qualquer seqüencia de caracteres antes ou depois dele


deve ser ignorada, por exemplo: '% de Tal' irá ignorar o que
estiver antes, enquanto que 'Fulano%' irá ignorar o que
estiver depois.
_: parecido com o %, exceto que ele ignora apenas um
caractere. Por exemplo: '_anderlei' nos resultaria tanto
'Wanderlei' quando 'Vanderlei'.
Banco de dados

Também é possível colocar mais de uma condição:

SELECT *
FROM Contato
WHERE nome LIKE '%de Tal'
AND telefone LIKE '(42)%'

Aqui queremos todos os registros que tem nomes terminando


com 'de Tal' e telefones começando com '(42)'.
Banco de dados

Também é possível selecionar apenas alguns campos:

SELECT codigo, telefone


FROM Contato

Nesse caso, o campo 'nome' não seria mostrado.


Banco de dados

Para tornar as coisas mais interessantes, vamos criar a tabela


"Endereco" e preenchê-la com alguns dados:
Banco de dados

E se quiséssemos que nossos contatos da tabela Contato


tivessem um endereço?

Para isso, precisamos editar a tabela Contato e criar um


campo lá. Para isso, clique em Tabelas, depois clique com o
botão direito sobre a tabela Contato e clique em "Editar". Uma
vez aberta, crie o campo 'codEndereco' com o mesmo tipo
usado no campo 'codigo' da tabela "Endereco".
Banco de dados

Salve e feche a tabela e vá no menu Ferramentas - Relações.


Na janela que se abre, adicione as duas tabelas, depois feche
a janela "Adicionar tabelas".
Banco de dados

A seguir, na tabela Contato, clique sobre o campo


'codEndereco' e arraste-o em cima do campo 'codigo' da tabela
Endereco:

O relacionamento será criado:


Banco de dados

Salve e feche a janela. Agora vamos entender o que é um


relacionamento.

Não precisamos colocar todas as informações em uma só


tabela. Isso desorganizaria tudo e deixaria o banco de dados
difícil de lidar.

Ao invés disso, podemos separar as informações em tabelas


diferentes e criar relacionamento entre elas.
Banco de dados

Um relacionamento é basicamente uma ligação entre uma


tabela e outra. Para criar um relacionamento, é necessário um
campo na tabela referenciadora do mesmo tipo de dados da
chave primária da tabela referenciada.

Entretando, isso não é o suficiente, é necessário especificar o


relacionamento. No idioma de bancos de dados, um
relacionamento é uma chave estrangeira, ou seja, um campo
que contém o valor da chave primária de outra tabela.
Banco de dados

Os tipos de relacionamento são:

1-1: diz ao banco de dados que cada registro na tabela A


deve corresponder a apenas um registro na tabela B, por
exemplo: uma pessoa só pode ter um CPF.
1-n: cada registro na tabela A pode corresponder a vários
registros na tabela B, por exemplo: uma pessoa pode ter
vários endereços.
n-n: vários registros na tabela A podem corresponder a
vários registros na tabela B, por exemplo: várias pessoas
podem comprar em várias lojas diferentes.
Banco de dados

Uma relação N-N deve ser convertida em uma nova tabela,


caso contrário a organização dos dados ficaria muito confusa.

Usando o mesmo exemplo das pessoas que comprar em


várias lojas, deveríamos criar uma tabela do tipo
"Pessoa_Loja" para nos dizer qual pessoa corresponde a qual
loja e vice-versa.

A tabela Pessoa teria uma relação 1-N com essa tabela, assim
como essa nova tabela teria uma relação N-1 com a tabela
Loja.
Banco de dados

Continuando, vamos usar o editor de dados para dar um


endereço aos nossos contatos:

Note que se você tentar informar um código de endereço que


não exista, receberá um erro.
Banco de dados

Agora, como podemos selecionar os dados do endereço junto


com os dados do contato?

SELECT *
FROM Contato c
INNER JOIN Endereco e ON e.codigo = c.codEndereco

Aqui demos um apelido ('c') à tabela Contato e a unimos


('INNER JOIN') com a tabela Endereco. Para realizar uma
união é necessária uma condição ('ON').

No exemplo, a união é feita quando o código do endereço é


igual ao valor do campo 'codEndereco' da tabela Contato.
Banco de dados

Assim, temos como resultado:


Banco de dados

Novamente, podemos escolher os campos que queremos


mostrar:
Banco de dados

Também podemos continuar filtrando normalmente:


Banco de dados

Para inserir um registro dentro de uma tabela o comando é o


seguinte:

INSERT INTO Contato (codigo, nome, telefone)


VALUES (4, 'Aparecido de Jesus', '(53) 3433-334')

Esse comando não é compatível com o Base, embora seja


SQL padrão.

O comando INSERT tem como parâmetro o nome da tabela e


quais campos serão preenchidos. O comando VALUES recebe
os valores que serão inseridos. A ordem dos valores (VALUES)
será a mesma informada no INSERT.
Banco de dados

Para alterar um registro:

UPDATE Contato
SET telefone = '(33) 3333-3333'
WHERE codigo = 1

O comando de alteração (UPDATE) precisa de novos valores


(SET) e uma condição (WHERE). Caso seja necessário alterar
mais de um valor, basta separar com vírgula.

UPDATE Contato
SET telefone = '(33) 3333-3333',
nome = 'Não sou mais Fulano de Tal'
WHERE codigo = 1
Banco de dados

Para remover um registro:

DELETE FROM Contato


WHERE codigo = 3

Esse comando não precisa de muita explicação. Ele irá apagar


(DELETE) da tabela especificada os valores que
corresponderem à condição (WHERE).
Banco de dados

Eu devo confessar que o Base não é um dos melhores


sistemas de bancos de dados que existe.

Para cada necessidade existe um sistema diferente, por


exemplo: o Oracle e o SQL Server são excelentes para
trabalhar com grandes quantias de dados e de requisições,
enquanto que o Firebird é ótimo para aplicações pequenas.

O Base nos foi muito útil até agora, mas apenas como
ferramenta de aprendizado. Chegou a hora de partir para algo
novo e mais completo.
Banco de dados

Em primeiro lugar, quero que baixe e instale o SQLite


Administrator: http://sqliteadmin.orbmu2k.de/

Ele é uma ferramenta gráfica para o sistema SQLite, que é um


banco de dados leve e indicado para aplicações pequenas.

A parte boa do SQLite é que não é necessário um servidor


para que ele seja acessado, como geralmente acontece com
os sistemas de bancos de dados mais robustos.

Como um jogo (exceto se for um MMO) não precisa de um


banco de dados muito poderoso, o SQLite nos cai como uma
luva.
Banco de dados

Vamos recriar o banco de dados original que desenvolvemos


para a nossa Agenda. No SQLite Administrator, clique no botão
"Criar Banco de Dados" e salve-o na mesma pasta do arquivo
"agenda.py"
Banco de dados

Agora vamos criar a tabela Contato. Para isso, clique com o


botão direito sobre "Tabelas" e depois em "Criar tabela".
Banco de dados

Dê um nome à tabela e adicione o campo 'CODIGO',


configurado como sendo do tipo numérico, como chave
primária e como autoincremento.
Banco de dados

Autoincremento quer dizer que o campo terá seu valor


preenchido automaticamente. Sempre com um valor maior que
o último. Agora crie os demais campos:
Banco de dados

Quando terminar, clique em "Criar". Feito isso, selecione a


tabela "Contato" e vá até o editor de dados para adicionar
alguns registros:
Banco de dados

Quando terminar, clique no botão "Post" para que os dados


seja, de fato, gravados. Depois disso você pode fechar o
SQLite Administrator.
Banco de dados

Abra o arquivo "agenda.py" e remova o seguinte trecho:


for linha in open (CAMINHOARQUIVO):
split = linha.split(']')
novoContato = Contato(None, None, None)

for item in split:


novoItem = item.replace('[codigo', '').replace('[nome', '')
novoItem = novoItem.replace('[telefone', '').replace('\n', '')
novoItem = novoItem.replace('\xef\xbb\xbf', '')
if split.index(item) == 1:
novoContato.codigo = novoItem
elif split.index(item) == 2:
novoContato.nome = novoItem
elif split.index(item) == 3:
novoContato.telefone = novoItem
contatos.append(novoContato)
Banco de dados

Remova também este trecho:


arquivo = open(CAMINHOARQUIVO, 'w')
for contato in contatos:
linha = '[codigo]' + contato.codigo + '[nome]' + contato.nome + '[telefone]' + contato.telefone + '\n'
arquivo.write(linha)
Banco de dados

Altere o seguinte trecho:


#-*- coding: utf-8 -*-
import os
CAMINHOARQUIVO = os.path.dirname(os.path.abspath(__file__)) + '\\agenda.txt'

Para isto:
#-*- coding: utf-8 -*-
import sqlite3
import os

conexao = sqlite3.connect(os.path.dirname(os.path.abspath(__file__)) + '\\banco.s3db')


cursor = conexao.cursor()
Banco de dados

NO trecho que adicionamos, importamos o módulo 'sqlite3',


criamos a conexão com nosso novo banco de dados e criamos
um cursor que atua sobre a conexão.

Um cursor é um objeto que é capaz de interagir com o banco


de dados nos permitindo executar comandos SQL e trabalhar
com os dados retornados por eles.
Banco de dados

Altere a classe contato para que fique assim:

class Contato:
codigo = None
nome = None
telefone = None

def __init__ (self, novoNome, novoTelefone):


self.nome = novoNome
self.telefone = novoTelefone

Aqui removemos o parâmetro 'codigo' do construtor. Fizemos


isso, pois o banco de dados irá se encarregar de gerar um
código para nós (autoincremento).
Banco de dados

Abaixo do trecho:

contatos = []
op = 0

Adicione:

cursor.execute('SELECT * FROM CONTATO')

for linha in cursor:


novoContato = Contato(linha[1], linha[2])
novoContato.codigo = linha[0]
contatos.append(novoContato)
Banco de dados

O que fizemos foi executar uma SQL para selecionar todos os


contatos do banco de dados. Isso retorna ao cursor uma lista
de dados.

Para cada registro retornado, criamos um novo objeto Contato


e o adicionamos à lista de contatos do nosso programa.

Cada registro é retornado na forma de lista, portanto


precisamos do índice de cada campo para saber seu valor.
Banco de dados

Altere o trecho que trata a opção número 2 para que fique


assim:
elif op == 2:
print 'Nome: '
nome = raw_input()
print 'Telefone: '
telefone = raw_input()
novoContato = Contato (nome, telefone)
cursor.execute("INSERT INTO CONTATO(nome, telefone) VALUES('" + nome + "','" + telefone + "')")
conexao.commit()
cursor.execute('select * from contato where codigo = (select max(codigo) from contato)')
for linha in cursor:
novoContato.codigo = linha[0]
contatos.append(novoContato)
Banco de dados

O que fizemos foi executar uma SQL de inserção (INSERT)


contendo os dados do novo registro criado pelo usuário.

Note que quando o valor de um campo é string, ele deve estar


entre aspas simples ('') na SQL. Por isso usamos os dois tipos
de aspas aqui.

Depois, chamamos o comando 'commit' do objeto de conexão,


o que vai efetuar, de fato, a gravação dos dados. Finalmente
executamos uma SQL que seleciona o ultimo registro
adicionado e coloca o valor do campo código no novo registro
e o adiciona à lista.
Banco de dados

Altere a opção número 3 para ficar assim:


elif op == 3:
print u'Código: '
codigo = int(raw_input())
for contato in contatos:
if contato.codigo == codigo:
print 'Novo nome: '
contato.nome = raw_input()
print 'Novo telefone: '
contato.telefone = raw_input()
cursor.execute("UPDATE CONTATO SET nome = '" + contato.nome + "', telefone = '" + contato.telefone +"'
WHERE codigo = " + str(codigo))
conexao.commit()
break
Banco de dados

Aqui não mudou muito, simplesmente no fim do código


colocamos uma SQL que atualiza (UPDATE) o registro com o
código especificado.

Como no banco de dados o campo 'codigo' é do tipo numérico,


foi necessário fazer o casting da entrada de dados do usuário
('int(raw_inuput())').
Banco de dados

Altere a opção 4 para ficar assim:


elif op == 4:
print u'Código: '
codigo = int(raw_input())
for contato in contatos:
if contato.codigo == codigo:
cursor.execute('DELETE FROM CONTATO WHERE codigo = ' + str(codigo))
contatos.remove(contato)
print 'Contato removido!'
break

Novamente, não houve uma grande mudança, apenas a


colocação da SQL que remove (DELETE) o registro do banco
de dados.
Banco de dados

Com isso, nosso programa da agenda já deve funcionar


perfeitamente com o banco de dados.

Note que a implementação da idéia tornou-se mais fácil com o


uso do banco de dados do que foi quando usamos arquivos.

Basta ter uma conexão, um cursor, alguns comandos SQL


para cada finalidade e pronto!
Banco de dados

Isso é tudo que você precisa saber por enquanto sobre banco
de dados. Recomendo que reveja as partes que não entendeu
antes de prosseguir.

Como sempre, ainda existe muito a se falar sobre banco de


dados. O que aprendemos aqui foi o básico da DML (Data
Manipulation Language), que serve para trabalhar
especificamente com os dados e não com a estrutura do banco
de dados em si.
BGE
Escrever programas para
console não é lá muito
empolgante, não é?

É agora que as coisas


começam a ficar mais
interessantes - e mais
ilustradas, prometo!

Para essa parte do curso,


o requerimento é algum
conhecimento básico do
Blender.
BGE

Se você não for necessariamente um expert em modelagem,


texturização, animação, etc... o melhor a se fazer é utilizar
modelos prontos que podem ser baixados nos repositórios que
já indiquei anteriormente.

Deste ponto em diante, vou realmente precisar que você


conheça pelo menos o básico do Blender. Caso não conheça,
então recomendo que procure alguns tutoriais básicos sobre a
interface do programa, modelagem, animação, texturização,
etc.

Pronto para começar?


BGE
Por enquanto, nossos objetos
de aprendizado serão os que
já são criados na cena padrão
do Blender (cubo, lamp e
camera).

Antes da diversão realmente


começar, devemos conhecer o
fabuloso mundo dos Logic
Bricks.

Para isso, selecione o cubo


como na imagem e tecle F4
para ir ao Painel de Lógica.
BGE

Esse painel é dividido em duas partes: a configuração do ator


(actor) e as configurações dos blocos de lógica (logic bricks):

Note que as configurações dos blocos de lógica são dividos em


três: sensores (sensors), controladores (controllers) e
atuadores (actuators).
BGE

O ator é o próprio objeto (no caso, o cubo) como uma entidade


dentro da BGE, ou seja, dentro do jogo ele não é mais um
objeto do Blender, mas sim da BGE.
A primeira configuração que devemos
observar é o tipo de objeto (Object type).

Note que, por padrão, o tipo de objeto é


definido como static (estático).
BGE

O primeiro tipo é o soft body. Esse tipo de objeto deforma com


colisões físicas. Suas propriedades são:

Actor: diz à BGE para calcular a Física do objeto


Ghost: faz com que o objeto possa atravessar outros
objetos
Invisible: o objeto não aparecerá no jogo
Advanced: configurações avançadas de colisão
Mass: quantidade de força necessária para mover o objeto
Shape Match: habilita a deformação conforme a forma
Bending const: habilita restrições de deformação
LinStiff: rigidez linear das juntas do softbody
Friction: fricção física
KMT: início da deformação conforme a forma
BGE
O segundo tipo é o rigid body. Esse tipo de objeto é duro, ao
contrário do soft body e tende a rolar. Suas propriedades são:

Actor: diz à BGE para calcular a Física do objeto


Ghost: faz com que o objeto possa atravessar outros
objetos
Invisible: o objeto não aparecerá no jogo
Advanced: configurações avançadas de colisão
Mass: quantidade de força necessária para mover o objeto
Radius: tamanho da área de cálculo da Física do objeto
No sleeping: calcula a Física no objeto, mesmo em repouso
Damp: resistência ao movimento do objeto
RotDamp: resistência à rotação do objeto
DoFh: habilita o suporte às propriedades físicas de material
BGE

RotFh: usa as normais das faces para o calculo do DoFh


Form: fator de inércia na Física do objeto
Anistropic: quantidade de fricção nos eixos X, Y e Z

O tipo de objeto dynamic é praticamente idêntico ao rigid body


e a diferença é que o rigid body é específico para objetos que
tendem a rolar, enquanto que o dynamic não é.
BGE

O quarto tipo é o static. Esse tipo de objeto é duro, mas não é


afetado pela gravidade. Suas propriedades são:

Actor: diz à BGE para calcular a Física do objeto


Ghost: faz com que o objeto possa atravessar outros
objetos
Invisible: o objeto não aparecerá no jogo
Advanced: configurações avançadas de colisão
Anistropic: quantidade de fricção nos eixos X, Y e Z
BGE

O quinto tipo é o sensor. Esse tipo de objeto não colide com


outros, ou seja, eles o atravessam. Ele detecta objetos rigid
body e dynamic, mas não detecta outros objetos do tipo
sensor. Suas propriedades são:

Detect Actor: detecta apenas objetos com a propriedade


Actor ativada
Invisible: o objeto não aparecerá no jogo
Advanced: configurações avançadas de colisão
BGE

O sexto tipo é o no collision. Esse tipo de objeto, assim como o


sensor, não é afetado pela física e deve ser usado quando
nenhum objeto pode colidir com ele, pois os objetos o
atravessarão.

Ele possui apenas a propriedade Invisible que faz com que o


objeto não apareça no jogo.
BGE

O sexto tipo é o occluder. Esse tipo de objeto não colide com


outros, ou seja, eles o atravessam. Ele tem a função de
impedir que objetos que estejam atrás dele sejam mandados
para a placa de vídeo. Isso é feito para economizar
processamento em alguns casos.

Ele possui apenas a propriedade Invisible que faz com que o


objeto não apareça no jogo.
BGE

Para os tipos de objetos que colidem, existe a configuração


dos bounds, ou seja, dos tipos de áreas de cálculo da Física
para um objeto.

Como calcular a Física para cada face de um objeto com


muitos vértices usaria muito processamento, a BGE trata o
objeto como uma forma mais simples, como um cubo ou uma
esfera para economizar processamento. É exatamente isso
que os bounds fazem.

Os tipos triangle mesh e convex hull devem ser usados para


cálculos mais precisos, como a colisão de um soft body numa
árvore, por exemplo.
BGE

Um objeto da BGE também pode possuir algumas


propriedades (properties), que nada mais são do que variáveis.
Elas podem ser do tipo timer (cronômetro), String (caracteres),
float (número decimal), int (número inteiro) e bool (lógico).

Para as propriedades temos:

Del: remove a variável


Type: tipo de dado
Name: nome da variável
Value: valor da variável
D: mostra o valor da variável no modo de depuração
(debug)
BGE

Sensores são entidades que capturam sinais, ou seja, eventos


específicos que acontecem no jogo. Como vários sinais
diferentes são enviados em um jogo, a BGE nos oferece vários
tipos de sensores.

O primeiro deles, o Always, retorna um sinal Verdadeiro o


tempo todo, ou seja, ele não é bem um sensor, mas uma
ferramenta para coisas dentro do jogo que precisar executar
sem parar, como tocar músicas de fundo, por exemplo.
BGE

Assim como todos os sensores, o Always tem os seguintes


parâmetros:

True level triggering: faz com que o retorno seja Verdadeiro


False level triggering: faz com que o retorno seja Falso
f: intervalo (em momentos) entre um retorno e outro
Level: faz o sensor detectar states
Tap: o sensor retornará apenas uma vez, mesmo que seja
do tipo Always. Bom para fazer inicializações.
Inv: inverte o retorno do sensor (de Verdadeiro para Falso e
vice versa)
BGE
O parâmetro 'f' é calculado da
seguinte forma:

Na BGE, 60 pulsos são 1 segundo


f=1: o sensor retorna uma vez a
cada pulso, ou seja, 60 retornos
por segundo
f=30: retorna uma vez a cada 30
pulsos, ou seja, 2 retornos por
segundo
f=60: retorna uma vez a cada 60
pulsos, ou seja, 1 vez por segundo
BGE

O tipo de sensor Delay nos oferece um maior controle sobre os


intervalos entre um retorno e outro. Seus parâmetros são:

Delay: intervalo (em momentos) entre um retorno e outro


Dur: duração do retorno (em momentos)
REP: reinicia o sensor depois que o retorno é enviado
BGE

O tipo Keyboard nos permite capturar teclas pressionadas pelo


jogador enquanto o jogo estiver sendo executado. Seus
parâmetros são:

Key: define uma tecla a ser capturada pelo sensor


All keys: captura qualquer tecla pressionada
Hold: teclas a serem seguradas enquanto se tecla a
primeira. Se key for 'W' e não houver Hold, o personagem
anda. Se key for 'W' e houver hold em 'Shift', o personagem
corre.
Log Toggle: variável Bool, que determina se haverá ou não
log de teclas.
Target: variável String onde o log será armazenado.
BGE

O Sensor do tipo Mouse, nos permite caputar eventos


realizados com o mouse. Suas opções são:

Left button: clique com o botão esquerdo


Right button: clique com o botão direito
Middle button: clique com o botão do meio
Wheel up: scroll para cima
Wheel down: scroll para baixo
Movement: movimento do ponteiro
Mouse over: ponteiro está sobre o objeto em que está
definido este sensor.
Mouse over any: ponteiro está sobre qualquer objeto.
BGE

O sensor do tipo Touch nos permite saber quando nosso


objeto está em contato (encosta) com outro. Quando o valor de
"MA" não está preenchido, retorna Verdadeiro sempre que
nosso objeto entra em contato com qualquer objeto na cena.

Se o valor de "MA" for preenchido com o nome de um material,


o sensor só irá retornar Verdadeiro quando nosso objeto entrar
em contato com objetos que estejam configurados com o
material em questão.
BGE

O sensor do tipo Collision é parecido com o Touch, a diferença


é que o Collision filtra os objetos por propriedade. Os
parâmetros são:

Pulse: permite ao sensor detectar mais de uma colisão ao


mesmo tempo
M/P: alterna entre o filtro por material e por propriedade
Property: define a propriedade (variável) a ser filtrada.
Somente objetos que possuam essa propriedade serão
detectados.
BGE

O sensor do tipo Near detecta se o objeto está a uma


determinada distância de outros objetos. Seus parâmetros são:

Property: filtra apenas objetos com uma determinada


propriedade.
Dist: distância (em unidades) dos objetos detectados para
retornar Verdadeiro
Reset: distância (em unidades) dos objetos detectados para
retornar Falso
BGE

Uma unidade da BGE é igual a uma unidade do


Blender. Um modo fácil de medir é observar o
número de "quadrados" na grid da 3D View.

O cubo padrão (imagem) tem duas unidades de


largura, duas de altura e duas de comprimento.

Isso pode ser provado colocando o cubo em


modo de edição (TAB) indo até o painel de
edição (F9) e habilitando-se a opção Edge
Length (largura de arestas).
BGE
BGE

O sensor do tipo Radar funciona de forma parecida com o


Near, exceto que o Radar funciona apenas para um eixo. Seus
parâmetros são:

Prop: filtro de objetos por propriedade


Type: eixo e direção a serem utilizados
Ang: ângulo de abertura do sensor
Dist: distância de alcance do sensor
BGE

Vamos comparar um sensor Near e um sensor Radar:

Near: cria um raio de 360º e tamanho determinado


em volta de si.

Radar: cria um raio de ângulo e tamanho


determinados em volta de si. O "cone" de detecção
irá atuar em somente um eixo.
BGE

O sensor do tipo Property nos permite avaliar o valor de uma


determinada propriedade. Seus parâmetros são:

Type: tipo de verificação. Pode ser equal (igual a), not equal
(diferente de), interval (está entre) e changed (mudou)
O parâmetro que aparece abaixo disso depende do tipo de
verificação escolhido. Value é um valor determinado, min e
max definem a faixa de comparação para o tipo interval.
BGE

O sensor do tipo Random retorna pulsos de forma aleatória, ou


seja, não há como se saber se o retorno vai ser Verdadeiro ou
Falso, pois ele retorna hora um, hora outro.

O parâmetro Seed refere-se a um valor inicial para a geração


dos sinais aleatórios. Se for igual a zero, o retorno não será
aleatório.
BGE

O sensor do tipo Ray funciona de forma parecida com o Radar,


exceto pelo fato de que ele "dispara" um raio na direção de um
determinado eixo . O raio segue pelo eixo até colidir com um
objeto qualquer ou que possua uma determinada propriedade.
Assim que isso acontece, o sensor retorna verdadeiro.

O botão X diz ao raio para atravessar objetos que não


possuam a propriedade especificada e continuar procurando.

O parâmetro Range, determina a distância máxima de alcance


do raio.

O parâmetro Type especifica o eixo e a direção do "disparo".


BGE

O sensor do tipo Message detecta quando uma mensagem é


enviada pelo jogo. Falaremos sobre mensagens mais adiante.

O sensor também permite filtrar as mensagens por um assunto


(Suject) específico.
BGE

O sensor do tipo Joystick trata eventos de um gamepad. Seus


parâmetros são:

Index: qual joystick usar (caso haja mais de um). O valor 0


indica o primeiro joystick
Type: tipo do evento a ser detectado no joystick
O parâmetro de baixo muda conforme o tipo de evento
escolhido. Em suma, o tipo hat trata dos comandos
direcionais digitais, axis trata dos comandos direcionais
analógicos, single axis trata de um eixo em particular nos
analógicos e button trata os botões de comando.
BGE
BGE

O sensor do tipo Actuator detecta quando um atuador (mais


tarde falaremos deles) é ativado.

Para que funcione, é necessário especificar um atuador no


parâmetro Act.
BGE

Controladores são entidades que avaliam o retorno dos


sensores, realizam validações neles e retornam um pulso aos
atuadores.

Somente dois deles precisam de parâmetros exatos: Python e


Expression. Todos os demais utilizam apenas os sensores
conectados a eles para fazer a validação.
BGE

Em resumo os tipos de controladores são:

AND: todos os sensores conectados devem retornar


Verdadeiro para que o controlador retorne Verdadeiro
OR: um ou mais sensores devem retornar Verdadeiro
XOR: apenas um sensor deve retornar Verdadeiro
NOR: nenhum sensor deve retornar Verdadeiro
XNOR: todos os sensores devem retornar o mesmo valor
(Verdadeiro ou Falso)
Expression: permite avaliar através de uma expressão
Python: permite avaliar através de um script em Pyhton
(falaremos disso mais tarde)
BGE

Um exemplo de expressão seria:

Nesse caso, o sensor Always retorna sempre Verdadeiro, mas


a condição definida na expressão diz que além disso, é preciso
que "propriedade" seja igual a um, logo esse controlador não
irá retornar Verdadeiro.
BGE

Atuadores são entidades que afetam o jogo ou os objetos dele


de alguma forma. Em resumo: eles executam uma ação.

O primeiro deles, o Motion move o objeto no qual está


configurado (ator). Há dois tipos de movimento: simple e servo.
BGE

O Simple motion aplica movimento e rotação a um objeto em


eixos determinados. O parâmetro Loc refere-se à quantia de
movimento nos eixos X, Y e Z, enquanto que o parâmetro Rot
refere-se à quantia de rotação nesses eixos.

O Servo motion aplica força (torque) a um objeto de forma a


tornar sua movimentação mais natural, uma vez que no mundo
real a velocidade de um corpo é resultado da força que ele
usou para conseguí-la.

Logo, o Servo só funciona para objetos do tipo que recebem


cálculos de Física.
BGE

Os parâmetros do Servo motion são:

Ref: objeto de referência para o cálculo (uma plataforma


móvel, por exemplo)
LinV: velocidade linear de referência. O atuador tenta se
manter na velocidades especificadas aqui
Limit: limita a velocidade nos eixos. Pode-se especificar
velocidades mínimas e máximas para cada eixo
P: coeficiente proporcional de erro
I: coeficiente integral de erro
D: coeficiente derivado de erro
BGE

O coeficiente de erro do Servo é a diferença entre a força atual


e a força especificada no parâmetro LinV.

Quando a força está diferente, o Servo aplica uma nova força


ao objeto. Essa força é proporcional ao erro atual (P) e
também à sua integral (I), que a soma dos erros mais recentes.

O coeficiente derivado é baseado na freqüência com que o


erro se altera.
BGE

O atuador do tipo Shape Action trabalha com as shapekeys


que um objeto possui. Os tipos são:

Play: executa a animação inteira uma vez (Play)


Flipper: executa para frente (frames 1, 2, 3) quando for
verdadeiro e para trás (frames 3, 2, 1) quando for falso
Loop Stop: repete a animação inteira enquanto for
verdadeiro e a pausa quando for falso
Loop End: repete a animação inteira enquanto for
verdadeiro e a reinicia quando for falso
Property: enquanto for verdadeiro, o frame atual é definido
por uma propriedade
BGE

O parâmetro AC recebe o nome da action a ser executada. Sta


refere-se ao frame inicial da animação, assim como End
refere-se ao frame final.

Blendin é ao número de quadros de sobreposição (transição)


entre uma animação e outra. Suaviza a troca de animações.
BGE

Priority indica a prioridade com que a animação deve ser


executada caso várias animações sejam executadas ao
mesmo tempo. Quando mais baixo o valor, maior a prioridade.

FrameProp recebe uma variável que irá armazenar o frame


atual.

O botão Continue indica que a animação iniciará no frame em


que parou da ultima vez que foi executada. Se estiver
desligado, a animação irá começar sempre do começo.
BGE

O atuador do tipo Action pode ser usado apenas por armatures


e funciona de forma semelhante ao Shape Action, exceto pelo
fato de que ele é específico para actions de armature.

Os parâmetros são os mesmos do Shape Action, por isso não


convém repetir o que já foi explicado.
BGE

O atuador do tipo Constraint serve para limitar a


movimentação, a rotação e a distância dos objetos. Seus tipos
são:

Location: limita a área na qual o objeto pode se mover


Distance: limita a distância que um objeto pode ficar de
outro
Orientation: limita a rotação do objeto em cada eixo
Force field: limita a distância e repele o objeto do outro
BGE

Para o tipo Location temos:

damp: atraso (em frames) para que a limitação ocorra


Limit: eixo e direção da limitação
Min: tamanho mínimo da área de limitação
Max: tamanho máximo da área de limitação
BGE

Para o Distance temos:

damp: atraso (em frames) para que a limitação ocorra


Direction: eixo e direção da limitação
Range: tamanho da área de cálculo
M/P: alterna entre o filtro por material ou propriedade
Property: somente limita se o objeto contiver a propriedade
PER: torna a limitação ativa o tempo todo
time: tempo máximo que a limitação fica ativa
rotDamp: atraso (em frames) para a rotação
N: usa as normais do objeto para calcular a limitação
Dist: distância a ser mantida do objeto
BGE

Para o Orientation temos:

damp: atraso (em frames) para que a limitação ocorra


Direction: eixo e direção da limitação
X: cosseno do ângulo no eixo X
Y: cosseno do ângulo no eixo Y
Z: cosseno do ângulo no eixo Z
time: tempo máximo que a limitação fica ativa
Min: ângulo mínimo do objeto
Max: ângulo máximo do objeto
BGE

Para o Force field temos:

damp: atraso (em frames) para que a limitação ocorra


Direction: eixo e direção da limitação
Fh: força de repulsão
M/P: alterna entre o filtro por material ou propriedade
Property: somente limita se o objeto contiver a propriedade
PER: torna a limitação ativa o tempo todo
time: tempo máximo que a limitação fica ativa
rotDamp: atraso (em frames) para a rotação
N: usa as normais do objeto para calcular a limitação
dist: distância a ser mantida do objeto
RotFh: deixa o objeto paralelo ao outro
BGE

O atuador do tipo Ipo serve para controlar animações com


curvas Ipo. Seus tipos e parâmetros são bastante parecidos
com os do tipo Action, exceto por:

Tipo Ping Pong: irá alternar entre animação para frente (Sta
para End) e para trás (End para Sta) sempre que for
verdadeiro
Child: aplica o atuador aos objetos que têm parent com o
ator
Force: converte o Ipo em força (física)
Add: soma os valores da Ipo ao atuais do objeto.
BGE

O atuador do tipo Camera é feito para seguir outro objeto de


maneira suave. Qualquer objeto pode usá-lo. Seus parâmetros
são:

OB: nome do objeto a ser seguido


Height: altura que a câmera deverá tentar manter do centro
do objeto seguido
Min: distância mínima que a câmera deverá tentar manter
do centro do objeto seguido.
Max: distância máxima que a câmera deverá tentar manter
do centro do objeto seguido.
X e Y: define em qual eixo a câmera será colocada.
BGE

O atuador do tipo Sound é usado para reproduzir sons dentro


da BGE. Seus tipos são:

Play Stop: toca desde o início e pára quando o som


terminar ou o atuador for falso.
Play End: toca desde o início, pára quando o som termina e
reinicia quando for verdadeiro.
Loop Stop: toca e reinicia enquanto for verdadeiro.
Loop End: toca sem parar (mesmo que seja falso) e reinicia
quando for verdadeiro.
Loop Ping Pong Stop: toca e reinicia enquanto for
verdadeiro, tocando também de trás para frente.
BGE

Loop Ping Pong: toca sem parar e reinicia quando for


verdadeiro, além de tocar também de trás para frente.

Os parâmetros são:

Volume: volume do som (de 0 a 1)


Pitch: tom/velocidade do som (de -12 a 12)
BGE

O atuador do tipo property serve para alterar as propriedades


(variáveis) do ator. Seus tipos são:

Add: soma um valor a uma propriedade


Assign: atribui um valor a uma propriedade
Copy: copia o valor de uma propriedade de outro objeto
Toggle: Inverte o valor de uma propriedade

O tipo toggle alterna de 0 para 1 (Int), de True para False


(Bool), de 1.0 para 0.0 (Bool) e vice-versa. Além de reiniciar
propriedades do tipo Timer.
BGE

Seus parâmetros são:

Prop: nome da propriedade a ser alterada


Value: valor a ser atribuído ou somado à propriedade
OB: objeto que contém a propriedade a ser copiada
Prop (OB): propriedade de outro objeto a ser copiada
BGE

O atuador do tipo Edit Object serve para alterar a malha de um


objeto, acrescentar ou remover objetos, entre outras operações
do tipo. Seus tipos são:

Add Object: adiciona uma cópia de um objeto à cena


Dynamics: altera o cálculo da Física no ator
End Object: remove o objeto da cena
Replace Mesh: troca a malha (mesh) do ator
Track To: faz o ator seguir (acompanhar) um objeto
BGE

Para o tipo Add Object temos:

OB: nome do objeto a ser criado


Time: tempo de vida do novo objeto (0 = infinito)
linV: velocidade linear inicial do novo objeto nos eixos X, Y
eZ
AngV: velocidade angular inicial do novo objeto nos eixos
X, Y e Z
BGE

Para o tipo Dynamics temos:

Restore Dynamics: restaura o cálculo de Física no ator


(depois de suspendo)
Suspend Dynamics: suspende o cálculo de Física no ator
Enable Rigid Body: habilita o rigid body no ator
Disable Rigid Body: desabilita o rigid body no ator
Set Mass: altera a massa do ator
BGE

Para o Replace Mesh temos o parâmetro ME que deve conter


o nome da nova malha a ser definida para o objeto.

Para o Track To temos:

OB: nome do objeto a ser acompanhado


Time: tempo de duração do acompanhamento (0 = infinito)
3D: segue o objeto nos três eixos
BGE

O atuador do tipo Scene nos permite realizar alterações


diretamente na cena do jogo. Seus tipos são:

Add Background Scene: adiciona uma cena atrás da cena


atual
Add Overlay Scene: adiciona uma cena sobre a cena atual
Remove Scene: remove uma cena
Restart: reinicia a cena atual
Resume Scene: continua a cena atual
Suspend Scene: pausa a cena atual
Set Camera: define a camera ativa para a cena atual
Set Scene: define uma cena como sendo a cena atual
BGE

A maioria dos tipos possui o parâmetro SCE, que é o nome da


cena que se quer realizar a operação.

O tipo Camera possui o parâmetro OB que deve conter o nome


da câmera a ser definida como ativa.
BGE

O atuador do tipo Random serve para gerar valores aleatórios


e guardá-los dentro de propriedades. Seus tipos são:

Bool Bernoulli: chance de ser verdadeiro ou falso é


determinada por uma porcentagem
Bool Constant: sempre verdadeiro ou sempre falso
Bool Uniform: 50% de chance de ser verdadeiro ou falso
Float Constant: sempre retorna o mesmo número decimal
Float Neg Exp: o número decimal retornado é baseado num
tempo de "meia-vida"
Float Normal: retorna decimais baseado em uma média e
um desvio
BGE

Float Uniform: retorna um número decimal entre uma faixa


Int Constant: retorna sempre o mesmo número inteiro
Int Poisson: retorna números inteiros baseado numa média
Int Uniform: retorna um número inteiro entre uma faixa

Os parâmetros para cada tipo são, em geral, auto-explicativos


se você leu o que cada tipo faz. Todos os tipos possuem o
parâmetro Seed, que é o número inicial da geração aleatória.
BGE

O atuador do tipo Message serve para enviar uma mensagem


a todos os atores na cena. Essas mensagens serão recebidas
por um sensor do tipo Message nesses objetos. Seus
parâmetros são:

To: nome do objeto para se enviar a mensagem (em branco


= todos os objetos)
Subject: título (assunto) da mensagem. É opcional
T/P: alterna entre enviar um texto ou o valor de uma
propriedade
Body: texto da mensagem
Propname: nome da propriedade cujo valor será enviado
BGE

O atuador do tipo CD é usado para se controlar um CD de


áudio dentro do CD-ROM. Seus tipos são:

Play all tracks: toca o CD do início ao fim


Play one track: toca apenas uma faixa específica
Pause: pausa a reprodução do CD
Resume: retoma a reprodução do CD
Stop: Pára a reprodução do CD
Volume: Altera o volume do áudio do CD

Novamente, os parâmetros são auto-explicativos.


BGE

O atuador do tipo Game nos permite realizar operações


diretamente no comportamento da BGE. Seus tipos são:

Restart this game: reinicia o jogo atual


Start new game: inicia um novo jogo
Quit this game: encerra o jogo atual
Load: carrega o dicionário global do disco para o jogo atual
Save: salva o dicionário global do jogo atual para o disco
BGE

Para o tipo Start new games temos o parâmetro File que deve
conter o nome de um arquivo .blend a ser carregado e iniciado.

Os tipos Save e Load atuam sobre um dicionário global, que é


nada mais do que o "estado" da BGE. É a mesma coisa que as
funções de salvar e carregar dos jogos.

O dicionário é salvo como NomeDoJogo.bgeconf na mesma


pasta em que está o .blend do jogo.
BGE

O atuador do tipo Visibility serve para alterar a visibilidade do


ator. Seus parâmetros são:

Visible: torna o ator visível ou invisível (botão desativado)


Occlusion: faz com que os objetos atrás do ator não sejam
visíveis
Children: aplica o atuador aos objetos que tiverem parent
com o ator.
BGE

O atuador do tipo 2D Filter aplica filtros gráficos ao ator. Seus


tipos são:

Blur: desfoca o objeto


Custom Filter: permite ao usuário usar um filtro próprio
Dilation: aumenta áreas mas claras
Disable Filter: desabilita (mas não remove) um filtro com o
número de passos especificado
Enable Filter: habilita um filtro com o mesmo número de
passos especificado
Erosion: aumenta áreas mais escuras
GrayScale: remove todas as cores, deixando apenas tons
de cinza
BGE

Invert: inverte as cores e intensidade das luzes


Laplacian: destaca regiões onde ocorrem mudanças
rápidas e intensas
Motion blur: desfoca quando o ator se move
Prewitt: calcula a orientação (rotação) local das arestas
(edges)
Remove filter: remove um filtro com o mesmo número de
passos especificado
Sepia: converte todas as cores em tons de amarelo e
marrom
Sharpen: aumenta o contraste entre pixels (nitidez)
Sobel: calcula o gradiente da intensidade da imagem
BGE

Todos os filtros possuem o número de passos (Pass Number),


que em resumo é a qualidade do filtro. Quanto maior o número
de passos, mais vezes o mesmo cálculo será feito para aquele
filtro.

No tipo Custom Filter, deve-se especificar o nome de um


arquivo ".py" que esteja carregado no Text Editor.
BGE

O atuador do tipo Parent nos permite tornar o ator "filho" de


outro objeto na cena ou remover essa relação. Seus tipos são:

Remove Parent: remove a ligação parent entre o ator e o


objeto
Set Parent: define outro objeto na cena como parent (pai)
do ator

O parâmetro Compound adiciona a forma do filho à forma do


pai. Para que funcione, os bounds de ambos devem ser do tipo
Compound. O parâmetro Ghost torna o objeto insensível a
colisões enquanto o parent estiver ativo.
BGE

O atuador do tipo State serve para alterar o estado (state) do


ator. Seus tipos são:

Add: ativa os states selecionados e não altera os demais


Cpy: ativa os states selecionados e desativa os demais
Inv: se os states selecionados estiverem ativos, os desativa
e vice-versa
Sub: desativa os states selecionados e não altera os
demais
BGE

O sistema de states da BGE foi criado para agrupar blocos de


lógica dentro de estados específicos. Por exemplo: nosso
personagem pode se comportar de maneiras diferentes dentro
da água, andando sobre gelo ou em terra firme, certo?

Nesse caso, devemos criar um state para cada um desses


comportamentos. Dê uma olhada no controlador abaixo:
BGE

O controlador mostrado possui um controlador do tipo AND no


state número 1. Isso é representado pelo círculo semi-
transparente. Se selecionarmos o estado número 2 e
adicionarmos um novo controlador, ficaria assim:

Agora esse controlador trabalha em dois states diferentes


(círculos semi-transparentes), sendo que estamos visualizando
o state número 2 (selecionado). Também é possível ver o state
atual ao lado do botão com o ícone da estrela.
BGE

Um exemplo simples usando o cubo padrão:

O state marcado com o círculo preto é state inicial. Para fazer


isso, segure Ctrl e clique nele.
BGE

No state número 1 temos:

Aqui o sensor para a barra de espaços torna o ator invisível e


ativa o state número 2.
BGE

No state número 2 temos:

Aqui o sensor para a barra de espaços irá deixar o ator visível


e ativar o state número 1. Temos um ciclo que nos permite
alterar a visibilidade do ator teclando a barra de espaços.
BGE

Seguindo adiante, vamos aprender um pouco sobre os


módulos da BGE. Para fazer isso, configure o cubo padrão
assim:

Note que o nome "meuScript.py" é válido, pois ele existe no


Text Editor (parte superior da imagem). Também é uma boa
ativar os botões mostrados na imagem no Text Editor.
BGE

A BGE nos oferece cinco módulos principais:

GameKeys: trata as teclas do teclado


GameLogic: módulo principal das funções da BGE
Mathutils: funções matemáticas úteis à BGE
PhysicsContraints: trata a Física da BGE diretamente
Rasterizer: trata a renderização em tempo real

O módulo que mais iremos utilizar será o GameLogic. É uma


boa ter sempre uma referência sobre os módulos. Eu utilizo
essa: http://www.tutorialsforblender3d.com/GameFunctions/ClassIndex_1.html
BGE

No guia de referência podem ser encontrados todos os


módulos e classes da BGE, bem como suas funções e
variáveis em detalhes. Isso é muito útil caso surja alguma
dúvida.

O básico do script para a BGE é o seguinte:


import GameLogic as g

cont = g.getCurrentController()
obj = cont.owner
BGE

No exemplo, importamos o módulo GameLogic com o apelido


de "g".

Em seguida, criamos uma variável (cont) que recebe o


controlador atual, ou seja, o controlador no qual o script está
definido. No caso do exemplo com o cubo padrão, ele seria o
controlador do tipo Python chamado "cont".

Esse controlador é do tipo SCA_PythonContoller (consulte a


referência) e possui a variável 'owner', que retorna o ator
(objeto) que possui o controlador. No caso, atribuímos seu
valor (objeto OBCube) a uma variável (obj).
BGE

Simplificando:

Importamos o módulo GameLogic


Apelidamos o módulo como "g"
Capturamos o controlador ("cont") que está chamando o
script ("meuScript.py")
Capturamos o objeto ("OBCube") ao qual o controlador
("cont") pertence.

O nome de um objeto na BGE sempre deve ser precedido por


"OB". Se no Blender ele se chama "Cube", na BGE irá se
chamar "OBCube".
BGE

É muito importante que entenda esse script básico, portanto se


ainda tem alguma dúvida, volte um pouco e não continue até
entender o funcionamento do script.

Vamos complicar as coisas um pouco mais, configure o cubo


assim:

Note que dei o nome "movimento" ao atuador Motion.


BGE

Continuando nosso script:


import GameLogic as g

cont = g.getCurrentController()
obj = cont.owner
mov = cont.actuators['movimento']

O objeto 'cont' (tipo SCA_PythonController) tem a propriedade


'actuators', que contém todos os atuadores conectados ao
controlador pelos blocos de lógica.

O que fizemos, foi definir à variável 'mov' o valor dessa variável


no índice 'movimento', ou seja, agora 'mov' contém nosso
controlador do tipo Motion chamado "movimento".
BGE

import GameLogic as g

cont = g.getCurrentController()
obj = cont.owner
mov = cont.actuators['movimento']
mov.dLoc = [0, 0.02, 0]
cont.activate(mov)

Assim, é possível acessar a variável 'dLoc' do objeto 'mov' e


atribuir um valor a ela, o que seria o mesmo que definir o valor
de 'Loc' no bloco de lógica 'movimento'.

Finalmente, chamamos o método 'activate' do controlador que


ativa o atuador, ou seja, envia um sinal verdadeiro a ele. O
resultado é que ele é executado.
BGE

Complicando um pouco mais:

Note que dei o nome de 'espaco' ao sensor do tipo Keyboard


configurado para detectar a barra de espaços.
BGE

Logo:
import GameLogic as g

cont = g.getCurrentController()
obj = cont.owner
mov = cont.actuators['movimento']
esp = cont.sensors['espaco']

Assim como a propriedade 'actuators', temos a propriedade


'sensors', que contém todos os sensores conectados ao
controlador nos blocos de lógica.

No exemplo, capturamos o sensor 'teclado' e o atribuímos à


variável 'esp'.
BGE

Como o sensor do tipo Always faz com que nosso script seja
executado o tempo todo, logo nosso cubo irá se mover o
tempo todo. Para movê-lo apenas quando a barra de espaços
for pressionada, podemos fazer:
import GameLogic as g

cont = g.getCurrentController()
obj = cont.owner
mov = cont.actuators['movimento']
esp = cont.sensors['espaco']

if esp.positive:
mov.dLoc = [0, 0.02, 0]
cont.activate(mov)
else:
cont.deactivate(mov)
BGE

Aqui utilizamos a variável 'positive' que todo sensor possui


para saber se ele está ativo.

Colocamos seu valor em teste dentro de uma condição ('if'). Se o


sensor for positivo (verdadeiro), então movemos o cubo, caso
contrário desativamos o atuador ('deactivate').
BGE

Algumas mudanças:

Note que alterei o nome do sensor do tipo Keyboard para


"teclado" e ativei o All keys, que irá ativar o sensor sempre que
qualquer tecla for pressionada.
BGE

Como o nome do sensor mudou, também é preciso alterar o


script:
import GameLogic as g

cont = g.getCurrentController()
obj = cont.owner
mov = cont.actuators['movimento']
teclado = cont.sensors['teclado']

A idéia aqui é tratar as setas de direção, fazendo com que o


cubo se mova de acordo com a tecla pressionada.
BGE

Para facilitar, vamos importar o módulo GameKeys:


import GameLogic as g
import GameKeys as k

cont = g.getCurrentController()
obj = cont.owner
mov = cont.actuators['movimento']
teclado = cont.sensors['espaco']

Agora iremos utilizar a função 'getKeyStatus', que retorna o


código de status de uma determinada tecla. O módulo
GameKeys nos ajudará na hora de dizer a tecla desejada. Os
códigos de retorno que queremos são 1 (tecla recém-
pressionada) e 2 (tecla segurada).
BGE

Portanto:
import GameLogic as g
import GameKeys as k

cont = g.getCurrentController()
obj = cont.owner
mov = cont.actuators['movimento']
teclado = cont.sensors['teclado']

if teclado.getKeyStatus(k.UPARROWKEY) in [1, 2]:


mov.dLoc = [0, 0.02, 0]
cont.activate(mov)
elif teclado.getKeyStatus(k.DOWNARROWKEY) in [1, 2]:
mov.dLoc = [0, -0.02, 0]
cont.activate(mov)
elif teclado.getKeyStatus(k.LEFTARROWKEY) in [1, 2]:
mov.dLoc = [-0.02, 0, 0]
cont.activate(mov)

continua...
BGE

elif teclado.getKeyStatus(k.RIGHTARROWKEY) in [1, 2]:


mov.dLoc = [0.02, 0, 0]
cont.activate(mov)
else:
cont.deactivate(mov)

Com isso conseguimos tratar as setas do teclado. Note que


comparamos o retorno da função 'getKeyStatus' com uma lista,
de forma que se o retorno for algum dos valores da lista, a
condição retorna verdadeiro.

Note também que o valor do 'dLoc' do atuador muda de acordo


com cada caso.
BGE

Vamos criar uma propriedade chamada "tecla", do tipo String e


com o D (debug) marcado para o cubo:

Podemos acessar essa propriedade no nosso código também,


mas para facilitar, vá até o menu Game e clique em "Show
Debug Properties". Assim o valor dessa variável irá aparecer o
canto superior esquerdo da tela enquanto o jogo estiver sendo
executado.
BGE

Altere o trecho que trata cada tecla para que fique assim:
if teclado.getKeyStatus(k.UPARROWKEY) in [1, 2]:
mov.dLoc = [0, 0.02, 0]
cont.activate(mov)
obj.tecla = 'PARA CIMA'
elif teclado.getKeyStatus(k.DOWNARROWKEY) in [1, 2]:
mov.dLoc = [0, -0.02, 0]
cont.activate(mov)
obj.tecla = 'PARA BAIXO'
elif teclado.getKeyStatus(k.LEFTARROWKEY) in [1, 2]:
mov.dLoc = [-0.02, 0, 0]
cont.activate(mov)
obj.tecla = 'PARA A ESQUERDA'
elif teclado.getKeyStatus(k.RIGHTARROWKEY) in [1, 2]:
mov.dLoc = [0.02, 0, 0]
cont.activate(mov)
obj.tecla = 'PARA A DIREITA'
else:
cont.deactivate(mov)
obj.tecla = None
BGE

No exemplo, atribuímos um valor diferente para a propriedade


'tecla' do objeto 'OBCube' de acordo com cada caso.

Quando não há uma tecla das que tratamos sendo


pressionada, o valor é nulo (None).
BGE

Por hora, isso é o básico que você deve saber sobre o


desenvolvimento de scripts para a BGE.

Com tudo isso (e ainda há MUITO mais), você já deve ser


capaz de criar bons games com Python + BGE, usando banco
de dados.

Espero que esse material tenha sido de alguma utilidade para


você. Qualquer dúvida, sempre existe o fórum do Blender
Brasil.