POO, introdução

A programação é orientada não pela decomposição de tarefas mas pela identificação das entidades que constituem o problema e como são modelizadas e manipuladas

os mecanismos:
Encapsulamento;
Herança;

Encapsulamento:
integridade da informação numa única estrutura a informação, e as funções que trabalham essa informação
acesso à informação é muito controlada

Herança:
coisas em comuns entre conceitos
(funcionários, funcionário administrativo, gestor, …)
sub-classes, surgem as estruturas que derivadas ou herdar do “pai”

Polimorfismo:
poli, várias, morfismos, formas
a mesma instrução pode ser usada em diferentes ações com significado análogo

as Classes, têm:
Estruturas
Classes
Construtores
Destrutor
Funções membros inline
Membros variáveis estáticos
Funções membros estáticas
Funções membros constantes
Funções friend
Construtores – lista de inicialização
Construtores – membros constantes não estáticos
Construtores – membro referência
Membros variáveis inicializados na declaração ( C++11)
Construtores que chamam construtores ( C++11)
Membros default e delete ( C++11)

passagens por referencia vs passagem por valor

nas classes deve haver relações explicitas entre a estrutura e as funções surgem as funções membros
. é a notação para aceder aos membros das classes

os membros podem ser:
privados (por defeito se fosse uma struct era ao contrário), em privado, as variáveis públicas, as funções membro por norma (funções: set, imprimir..)

funções:
get, servem para obter valores, para comparar (retornam copias dos valores)
criamos as funções/métodos usando :: (por exemplo: Estrutura::get..)
:: são funções que pertencem à classe, não são globais

funções inline:
o código é expandido no local da chamada
funções pequenas
chamadas muitas vezes
p.e. detetar se um numero é par
declara-se a função com a expressão inline
inline int par(int numero){

}

funções overloaded:
têm o mesmo nome no mesmo contexto
distinguem-se pelo número de argumentos
p.e.
data(“11/11/11”);
data(11,11,11);
void data (char * s)
void data(int n1, int n2, int n3)

função destrutor:
funciona automaticamente, quando um objeto é destruído ou perde a validade;
podemos precisar numa classe;
usada quando o objeto é destruído e precisamos de executar uma ação de seguida;
libertar por exemplo um espaço de memória dinâmica
o destrutor não tem parâmetros como o construtores
Os objetos locais não estáticos são destruídos quando a execução do programa sai do bloco onde foram declarados.
Os objetos globais são destruídos quando o programa termina.
Os objetos dinâmicos são destruídos com o operador delete.
e os objetos são destruídos por ordem inversa da construção

funções com argumentos por omissão:
A lista de parâmetros com os valores por omissão deve estar apenas na declaração da função cuidado com os erros de ambiguidade (onde existe mais do que uma hipótese)

membros e funções membros estáticos:
têm que ser criados fora dos construtores
são partilhados por todos os objetos da classe
existe apenas uma única versão
está sempre fora dos objetos
p.e.
um predio e um elevador
o prédio tem andares que são objectos
o elevador é o membro estático, que todos usam
e quem usar o elevador pode deixar lá um aviso/atualização
(é uma especie de global na classe)
também existem funções estáticas
a chamada de uma função estática deve ser sempre com ::, mesmo se o objeto existir

funções
no fim, não altera os membros dos objetos

Funções membros constantes, const :
não podem alterar os membros variáveis do objecto
são funções de consulta
poem-se na declaração e na implementação
se um objecto é const, então todas as funções têm que ser const, mesmo que essa função não altere nada
Apenas uma função membro declarada como constante pode ser invocada por objectos constantes.
p.e.:
const int * p;
ou
int const * p;
const antes do *, o ponteiro é um ponteiro que só serve para consultar o apontado, não altera o apontado, mas pode ser apontando para outro local em memória
const depois do *, o ponteiro é constante, tem um endereço e não pode ter outro, não pode apontar para outro sitio
int * const p = &i;
ponteiro constante para constante, const antes e depois do *
const int * const p = &i;
ou
int const * const p = &i;
aponta para uma localização de memória e não se pode alterar essa localização de memória
e também não pode alterar o apontado

parâmetros do tipo ponteiro para constante:
apenas se passa o endereço
garantia de não se alterar a variável
p.e.:
void g(const Elemento * p) //eficiência e segurança
int main(){
Elemento val;
g(&val);
}
ou
void f(const Elemento & arg) //referencia por constante: eficiência e segurança – c++

Funções friend
é uma função que, não sendo membro da classe, tem acesso aos seus membros privados
cuidado que isto é uma quebra do encapsulamento e da integridade dos dados
só deve ser usada com uma justificação forte!

vectores:
notação:
vector v1 = {…};
ou
vector v1(..);
limpar vectores:
v1.clear()
percorrer vectores:
for (const string &c : canais0) {canais.push_back(c);}
ou usando interadores
for(auto it = canais0.begin; it!= canais0.end(); ++it){
canais.push_back(*it);
}
o iterador trata-se como se fosse um ponteiro

initializer_list:
é uma coleção de vectores constantes de um tipo especificado
p.e.
class Televisao{
public:
Televisao(initializer_list<string>canais0);
void setCanais(initializer_list<string>canais0);
}
para criar um objecto do tipo Televisao:
Televisao tv ={“um”, “dois”}; //tv é um objecto Televisao
Usar initializer_list como argumento:
tv.setCanais({“um”, “dois”});
Criar um objeto anónimo
tv = {“um”, “dois”};

inicialização de vectores com construtores:
class Televisao{
vector canais;
public:
Televisao(string canais0[], int n);
}
em que p.e.:
string canais[] = {“um”, “dois”};
Televisao tv = {canais, 2};
ou
Televisao tv {canais, 2};

dedução de tipo: auto
o compilador determina automaticamente o tipo de uma variável
p.e.:
vector::const_rever_interator pesquisa();
p.e.:
int tabela[10];
for(auto & elemento : tabela)
instrução
o uso da referência &, podemos alterar os elementos da coleção (mais eficiente, não faz cópias)
o não uso da referência &, é uma copia do coleção
ou em alternativa para obter eficiência e segurança
for(const auto & elemento : tabela) //não alteramos nada

o nulltpr, é uma constante que representa um ponteiro nulo
0 e NULL são do tipo int em funções overloaded

as referências:
é um outro nome para uma variável, é como que um ponteiro constante que automaticamente conduz ao objeto apontado
p.e.:
void f(int &n);

int main(){
int i =0;
f(i);
cout << x << endl; //100
}

void f(int &n){
n=100;
}

uma referencia como retorno:
int & f();
int x = 0;//global
int main(){
f() = 100;
cout << x << endl; // 100
}
int & f(){
return x;
}

………..construtores, membros constantes não estáticos:
se numa classe existem membros const é obrigatório inicializar no construtor
class Test
{
const int t;
public:
Test(int t0) : t(t0)

………..construtores, membro referência:
class Test2
{
int & t;
public:
Test2(int &t0) : t(t0)
{
};

int getT() const
{
return t;
}

};

int main()
{
int x = 10;
Test2 t2(x);
cout << t2.getT() << endl;

}

membro default:
construtor = default, damos à classe um comportamento default
respeita a inicialização na zona privada
assim o default disponibiliza

membro delete:
vai tornar indisponível a implementação de construtor por omissão, construtor por cópia, operador atribuição, e destrutor
assim o delete impede/proíbe que exista:
construtor por omissão, construtor por cópia, operador atribuição, e destrutor

………..Variáveis em memória dinâmica:
operador new: requisitar memória, e que invoca o construtor
operador delete: para libertar a memória dinâmica
p.e.:
pVar = new tipo;
delete pVar;
p.e.:
Produto* p = new Produto();
cout << p->getAsString() << endl;
delete p;

posso fazer uma reserva com:
int *v2 = new int() //() garantem que vem 0
delete v2

objectos em memória dinâmica:
uso do new, reserva memória para uma variável do tipo classe, e desencadeia o construtor
uso do delete, activa a execução do destrutor

p.e.:
class Ponto {
int x; // abcissa
int y; // ordenada
public:
Ponto() { cout << “Construindo \n”; x = 0; y = 0; }
~Ponto() { cout << “Destruindo \n”; }
void imprime() { cout << “x=” << x << ” y=” << y << endl; } }; int main(void) { Ponto * p = new Ponto; p->imprime();
delete p;
}

existe uma alternativa a:
Ponto * p = new Ponto;
que pode ser com argumentos
Ponto * p = new Ponto{2,2};
criando por exemplo:

criando por exemplo:
Ponto(int x0, int y0) { cout << “Construindo \n”; x = x0; y = y0; }

………..criar um array dinâmico de variváveis de um tipo:
criar:
Ponto * p = new Ponto[4];
libertar:
delete [] pVar

os operadores:
o ponteiro this:
implicitamente nas funções normal membro, não estáticia, a palavra this representa o objecto que invocou a função

………..operadores overloaded:
p.e. existem dois ou mais objectos de uma determinada classe
podemos querer aplicar os operadores que se usam para os tipos primitivos, como é o caso de:
+

*
/
%
=
+=
e vão ter as mesmas regras de prioridade e associatividade
expandidmos assim para operandos das classes
usamos assim o operator
p.e. operator+

………..operadores binários:
p.e.: se o operador estiver relacionado com a atribuição, =, em que os dois operandos não têm o mesmo estatuto é um operador membro, para dar resposta a z+=x ou (z+=x)=y, e também para dar resposta a operações de cadeia
public:
Complexo & operator+=( const Complexo & x); //operador membro
//global, mas membro da classe,
Complexo & Complexo::operator+=( const Complexo & x){
a += x.a;
b += x.b;
return *this; //estatuto de referência
}
//a opção agora é global, porque têm o mesmo estatutuo, são consultados apenas
Complexo operator+(const Complexo & x, const Complexo & y){
// const Complexo & -> para funcionar em cadeia, p.e., para responder a z = x + y +z; (exame)
return Complexo( x.getA() + y.getA() , x.getB() + y.getB() );
}
//e global
ostream & operator<<( ostream & saida, const Complexo & x){
// recebe cout: ostream & saida -> é alterado logo usa-se o &, com a informação do objecto
// ostream & operator -> para funcionar em cadeia, p.e., para responder a cout << x << y; (exame)
return saida << “(“<<x.getA() << ” , ” << x.getB() << “)”;
}
para fazer:
z = x + y;
cout << z << endl;

………..os operadores unários:
++

que podem ser:
pre-fixados (recomendado que sejam membros), p.e.: ++a, que vai ser interpretada como aa.operator++()
ou
pos-fixados (recomendado que sejam membros), p.e.: a++, que vai ser interpretada como aa.operator++(0)

p.e.:
pre-fixado
public:
Complexo & operator++();
e global
Compelxo & Complexo::operator++(){
a +=1;
retun *this;
}

pos-fixado
public:
Complexo operator++(int);
e global
Compelxo Complexo::operator++(int){
Complexo anterior(a,b); //guardamos o valor velho num outro objecto
a +=1;
retun anterior; //retornamos o velho
}
//neste caso não retrno uma referência

………..operador []
usado em classes, classes com coleções, como arrays ou vectores
operator[]()
x[y] é equivalente x.operator[](y)
serve:
para acedermos a um elemento da coleção, e quebra com o encapsulamento
p.e.:
class Tabela {
static const int DIM = 10;
static double erro;
double a[DIM];
int n; // numero de elementos utilizados
public:
// …
double & operator[](int i);
};
double Tabela::erro = 0;
usando:
double & Tabela::operator[](int i) {
if (i >= 0 && i < DIM) return a[i];
else {
cout << “\nIndice ” << i << ” fora dos limites”;
return erro;
}
}
int main() {
Tabela x;
x[0] = 20; // equivalente a x.operator[](0) = 20;
cout << “\n x[0]=” << x[0] << endl;
x[40] = 55;
}

………..operador chamada de função
usada em situações bidimensionais, por exemplo obter um numero de uma matriz bidimensional
usa dois parentesis curvos
operação tem que ser membro
chama.se usando operator()()
p.e.:
class Matriz {
static const int DIM = 10;
static double erro;
double a[DIM][DIM];
int lin; // numero de linhas utilizadas
int col; // numero de colunas utilizadas
public:
//….
double & operator()(int i, int j);
};
double Matriz::erro = 0;

double & Matriz::operator( )(int i, int j) {
if (i >= 0 && i < DIM && j >= 0 && j < DIM)
return a[i][j]; //com estatuto de referência
else {
cout << “\nIndices i=”
<< i << ” e j=” << j << ” fora dos limites”;
return erro;
}
}

int main() {
Matriz x;
x(1, 0) = 44; // x.operator()( 1,0) = 44; (escrever 44 lá..)
cout << “\n x(1,0)=” << x(1, 0);
x(-1, 100) = 12.1;
}

Tags : , , , , ,

POO, introdução III

………..herança
se for composição um classe tem outras classes
se for derivação, sendo um caso particular com caracteristicas adicionais
uma classe derivada: tem membros herdados, e membros adicionais

class Terrestre : public Veiculo { // classe derivada: Terrestre, classe base: Veiculo
int velocidade;
public:
// …
};
a classe derivada acede aos gets e sets das funções que herdou

class Terrestre : public Veiculo
por se usar public:
herança publica
os membros publicos da classe base, são também da classe derivada
e por essa via será também um membro publico da classe derivada

class Terrestre : private Veiculo
ou
class Terrestre : Veiculo
por se usar private:
os membros publicos da herança, são privados de terrestre

o uso de protected:
é um nivel de acesso
são visiveis na classe
nas classes derivadas são visiveis
no código exterior, que não a classe ou classe derivadas não são acessiveis

Forma de derivação
private
membros que na classe base são:
private
protected
public
na classe derivada são:
inacessíveis
private
private

Forma de derivação
protected
membros que na classe base são:
private
protected
public
na classe derivada são:
inacessíveis
private
private

Forma de derivação
public (normal)
membros que na classe base são:
private
protected
public
na classe derivada são:
inacessíveis
protected
public

p.e.:
class Veiculo {
int peso;
protected:
int comprimento;
public:
Veiculo( int p = 0, int c=0): peso (p), comprimento(c){}
int getPeso()const{ return peso; }
int getComprimento()const{ return comprimento; }
void setPeso( int p){ peso = p;}
void setComprimento( int c){ comprimento = c;}
};

class Terrestre : public Veiculo {
int velocidade;
public:
Terrestre(int p=0,int c=0,int vel=0):Veiculo(p,c) {
velocidade = vel;
}

int getVelocidade()const{ return velocidade; }

void setVelocidade( int vel){ velocidade = vel;}

void imprime(ostream & saida )const{
saida << “Peso: ” << getPeso() << endl;
saida << “Compr: ” << comprimento << endl;
saida << “Veloc: ” << velocidade << endl;
}
};

int main(){
Veiculo v(700);
cout << “Peso: ” << v.getPeso() << endl;
//cout <<“Compr:” << v.comprimento << endl; ERRO , é protected em veiculo

Terrestre t(600, 4, 90);
cout << “Peso: ” << t.getPeso() << endl;
//cout <<“Compr:” << t.comprimento << endl; ERRO, é protected em veiculo

cout<<“Veloc: “<< t.getVelocidade() << endl;
t.imprime( cout);
}

Quando um objecto de uma classe derivada é destruído, são chamados os destrutores por ordem inversa da ordem de derivação: primeiro o destrutor da classe derivada, depois o destrutor da classe base

situação:
temos duas classes iguais, temos que usar o nome da herança Herança::funcao

situação: uma classe derivada e composta
p.e.:
class Base {
int i;
public:
Base(int ii = 0) : i(ii) { cout << “Base(int ii)\n”; }
~Base() { cout << “~Base()\n”; }
void imprime(ostream& saida)const {
saida << “Base: i=” << i << endl;
}
};

class Membro {
int k;
public:
Membro(int kk = 0) : k(kk) { cout << “Membro(int kk)\n”; }
~Membro() { cout << “~Membro()\n”; }
void imprime(ostream& saida)const {
saida << “Membro: k=” << k << endl;
}
};
class Derivada : public Base {
int j;
Membro m;
public:
Derivada(int jj) : Base(jj), j(jj), m(jj) {
cout << “Derivada(int jj)\n”;
}
~Derivada() { cout << “~Derivada()\n”; }
void imprime(ostream& saida)const {
saida << “Derivada: j=” << j << endl;
Base::imprime(saida);
m.imprime(saida);
saida << endl;
}
};
int main() {
Derivada d(2);
cout << “\nValores em d:\n”;
d.imprime(cout);
// chamada ao destrutor para d
}

situação: a classe derivada nao tem construtor nem destrutor
p.e.:
class Base {
int i;
public:
Base(int ii = 0) : i(ii) { cout << “Base(int ii)\n”; }
~Base() { cout << “~Base()\n”; }
void imprime(ostream& saida)const {
saida << “Base: i=” << i << endl;
}
};

class Membro {
int k;
public:
Membro(int kk = 0) : k(kk) { cout << “Membro(int kk)\n”; }
~Membro() { cout << “~Membro()\n”; }
void imprime(ostream& saida)const {
saida << “Membro: k=” << k << endl;
}
};

class Derivada : public Base {
Membro m;
public:
void imprime(ostream& saida)const {
saida << “Derivada: \n”;
Base::imprime(saida);
m.imprime(saida);
saida << endl;
}
};

int main() {
Derivada d;
cout << “\nValores em d:\n”;
d.imprime(cout);
// destruição de d
}

análise:
surge o construtor gerado automaticamente
é chamado o construtor da base e do membro
e na destruição invoca o membro e depois a base
também é respeitado o funcionamento da base e derivada, pela ordem com que são construídos e destruídos

………..funções com tratamento especial relativamente à herança
situações:
Construtores:
um construtor de uma classe derivada chama explicitamente ou implicitamente o construtor da classe base correspondente.
Construtor por cópia:
no construtor por cópia de uma classe derivada é preciso chamar explicitamente o construtor por cópia da classe base.
Destrutores:
um destrutor de uma classe derivada chama o destrutor da classe base correspondente.
Operador atribuição:
a atribuição entre dois objectos de uma classe pode não ser suficiente para fazer a atribuição entre dois objectos de uma classe derivada. O operador atribuição não é herdado normalmente como pode ver-se no exemplo seguinte.

p.e.:

class Base {
int i;
public:
Base(int ii) : i(ii) {}
Base(const Base & b) : i(b.i) {
cout << “Base(const Base &)\n”;
}
Base & operator=(const Base & b){
i = b.i;
cout << “Base::operator=()\n”;
return *this;
}
void imprime( ostream & saida)const{
saida << “Base: i=” << i << endl;
}
};

class Membro {
int k;
public:
Membro(int kk) : k(kk) {}
Membro(const Membro& m) : k(m.k) {
cout << “Membro(const Membro&)\n”;
}
Membro & operator=(const Membro & m){
k = m.k;
cout << “Membro::operator=()\n”;
return *this;
}
void imprime( ostream & saida)const{
saida << “Membro: k=” << k << endl;
}
};

class Derivada : public Base {
int j;
Membro m;
public:
Derivada(int jj) : Base(jj), j(jj), m(jj) {}

void imprime( ostream & saida)const{
saida << “Derivada: j=” << j << endl;
Base::imprime(saida);
m.imprime(saida);
}
};
int main() {
Derivada d(2);
cout << “\nConstrução por copia : ” << endl;
Derivada d2 = d; // construção por copia
cout << “\nValores em d2:\n”;
d2.imprime(cout);
Derivada d3(3);
cout << “\nAtribuicao: ” << endl;
d3 = d; // atribuição

cout << “\nValores em d3:\n”;
d3.imprime(cout);
}

………..herança, composição e construtor por cópia
outra versão da classe Derivada, com construtor por cópia e operador atribuição explícitos.
se nada dissermos na derivada, o construtor que é chamado é o da base por omissão e ainda assim temos que ter em atenção de que Base pode preencher com coisas por default
assim é necessário que se explicitem nestas chamadas a lista de inicialização do construtor por cópia, seriam chamados em seus lugares os correspondentes pois caso não sejam, construtores por defeito. O sub-objecto adquirido por herança e os membros objectos seriam inicializados pelos construtores por defeito em vez de receberem cópias dos correspondentes sub-objectos do objecto da classe Derivada considerado origem da cópia.
p.e.:

class Base {
int i;
public:
Base(int ii) : i(ii) {}
Base(const Base& b) : i(b.i) {
cout << “Base(const Base &)\n”;
}
Base& operator=(const Base& b) {
i = b.i;
cout << “Base::operator=()\n”;
return *this;
}
void imprime(ostream& saida)const {
saida << “Base: i=” << i << endl;
}
};

class Membro {
int k;
public:
Membro(int kk) : k(kk) {}
Membro(const Membro& m) : k(m.k) {
cout << “Membro(const Membro&)\n”;
}
Membro& operator=(const Membro& m) {
k = m.k;
cout << “Membro::operator=()\n”;
return *this;
}
void imprime(ostream& saida)const {
saida << “Membro: k=” << k << endl;
}
};
class Derivada : public Base {
int j;
Membro m;
public:
Derivada(int jj) : Base(jj), j(jj), m(jj) {}
Derivada(const Derivada& d) : Base(d), m(d.m), j(d.j) {
cout << “Derivada(const Derivada&)\n”;
}
Derivada& operator=(const Derivada& d) {
Base::operator =(d);
m = d.m;
j = d.j;
cout << “Derivada::operator=()\n”;
return *this;
}
void imprime(ostream& saida)const {
saida << “Derivada: j=” << j << endl;
Base::imprime(saida);
m.imprime(saida);
}
};

………..polimorfismo, clases derivadas
uma espécie de, ou um tipo de, é uma herança
o upcasting, é feito do tipo ascendente, e não é preciso fazer nada, nenhum cast explicito.
p.e.:
class Veiculo {
/* … */
};
class Terrestre : public Veiculo {
/* … */
};
class Automovel : public Terrestre {
/* … */
};
assim é possivel que:
conversão de um ponteiro para Terrestre num ponteiro para Veiculo;
conversão de um ponteiro para Automovel num ponteiro para Veiculo;
conversão de uma referência para Terrestre numa referência para Veiculo;
conversão de uma referência para Automovel numa referência para Veiculo.
isto é:
class Veiculo {
/* … */
};
class Terrestre : public Veiculo {
/* … */
};
int main(){
Veiculo *p;
Veiculo v;
Terrestre t;
p=&v;
p=&t; // upcasting
Veiculo & r = t; // upcasting
}

p=&t; // upcasting
um ponteiro para uma classe base pode receber um endereço de um objecto de uma classe derivada ou derivada da derivada..
pode assim ser feito por inteiro ou pode ser feito por referencia:
Veiculo & r = t; // upcasting

o upcasting é sempre verdade
o downcasting nem sempre é verdade

uso na base da expressão virtual na base e nas suas funções (desta forma será sempre usada a referência para o objeto que é referido)
e na derivada faz-se uso nas funções de override

Um ponteiro ou uma referência para uma classe base podem apontar para, ou referir, um objecto dessa classe ou de uma classe derivada directa ou indiretamente e é invocada:
é executada a versão da função da classe correspondente ao ponteiro ou referência, se a função não for virtual;
é executada a versão da função correspondente à classe a que pertence o objecto, se a função for virtual;

p.e.:
class Veiculo { //classe base
int peso;
public:
Veiculo(int p = 0) : peso(p) {}
virtual void imprime(ostream& saida) const { //virtual
saida << “\nPeso: ” << peso << endl;
}
};

class Terrestre : public Veiculo { //classe derivada
int velocidade;
public:
Terrestre(int p = 0, int vel = 0) : Veiculo(p), velocidade(vel) {}
void imprime(ostream& saida)const override { //lidar com o virtual
Veiculo::imprime(saida);
saida << “Veloc: ” << velocidade << endl;
}
};

class Automovel :public Terrestre { //classe derivada de derivada
int cilindrada;
public:
Automovel(int p = 0, int vel = 0, int cil = 0) : Terrestre(p, vel), cilindrada(cil) {}
void imprime(ostream& saida)const override { //lidar com o virtual
Terrestre::imprime(saida);
saida << “Cilind: ” << cilindrada << endl;
}
};

class Aereo :public Veiculo {
int altura_voo;
public:
Aereo(int p = 0, int a = 0) : Veiculo(p), altura_voo(a) {}
//não tem imprime recebe por herança da base
};
ostream& operator<<(ostream& saida, const Veiculo& x) {
x.imprime(saida);
return saida;
}

int main() {
Veiculo* a[] = { // array de ponteiros para a classe base, Veiculo
new Veiculo(700), // inicialização
new Terrestre(800,80), // inicialização: upcasting
new Automovel(900,90,1400), // inicialização: upcasting
new Aereo(2000,50) // inicialização: upcasting
};
int n = sizeof(a) / sizeof(Veiculo*); //contar elementos
for (int i = 0; i < n; i++) //perocrrer o array
a[i]->imprime(cout); // ou cout << *a[i];

for (int i = 0; i < n; i++)
delete a[i];
}

………..polimorfismo, classes abstractas e funções virtuais
uma classe é abstracta se a classe tem pelo menos um função virtual pura
uma classe abstracta não pode criar objetos
uma classe abstracta pode ter ponteiros e referências
faz sentido existir um prototipo da função que representa apenas um interface comum das classes desta hierarquia
p.e.:
virtual string meio() = 0; // é uma função virtual pura e fica uma classe abstracta
e esta classe pode conter ou pode não conter uma definição da função.
vais er necessário definir na classe derivada todas as funções virtuais puras adquiridas por herança

a classe derivada continua abstracta, se não for concretizada pelo menos uma função virtual pura adquirida por herança e por esse motivo não pode haver objectos desta classe

p.e.:
class Veiculo { //classe abstracta
int peso;
public:
Veiculo(int p = 0) : peso(p) {}
virtual void imprime(ostream & saida) const = 0; //função abstracta, ou virtuais puras
virtual string meioOndeSeDesloca()const = 0; //função abstracta, ou virtuais puras
int getPeso()const { return peso; }
};

class Terrestre : public Veiculo {
int velocidade;
public:
Terrestre(int p = 0, int vel = 0) :
Veiculo(p), velocidade(vel) {}
void imprime(ostream & saida)const override {
saida << “\nPeso: ” << getPeso() << endl << “Veloc: ” << velocidade << endl;
} //faz o overide da função abstracta imprime, da base: herdou duas, concretizou uma
// não se define ainda a função meioOndeSeDesloca(), e por este motivo esta é uma classe abstracta
};

class Automovel :public Terrestre { //esta classe tem as duas funções concretas: concretizou meioOndeSeDesloca e redefiniu a concreta imprime
int cilindrada;
public:
Automovel(int p = 0, int vel = 0, int cil = 0) : Terrestre(p, vel), cilindrada(cil) {}
virtual void imprime(ostream & saida)const override {
Terrestre::imprime(saida);
saida << “Cilind: ” << cilindrada << endl;
} //redefine a função imprime
string meioOndeSeDesloca()const override {
return string(” desloca-se em estrada \n”);
}//herdou uma função asbtracta e concretizou
};
class Aereo :public Veiculo { //concretizou as duas funções, logo é uma classe concreta
int alturaVoo;
public:
Aereo(int p = 0, int a = 0) : Veiculo(p), alturaVoo(a) {}
void imprime(ostream & saida)const override {
saida << “\nPeso: ” << getPeso() << endl << “Altura de voo: ” << alturaVoo << endl;
}
string meioOndeSeDesloca()const override {
return string(” desloca-se por via aerea \n”);
}
};
ostream & operator<<(ostream & saida, const Veiculo & x){
x.imprime(saida);
return saida;
}
int main() {
Veiculo* a[] = { //pode-se criar um array de ponteiros de classes abstractas
//new Veiculo(700), // ERRO, é uma classe abstracta, e não se podem criar objectos de classes abstractas
//new Terrestre(800,80), // ERRO, é uma classe abstracta, e não se podem criar objectos de classes abstractas
new Automovel(900,90,1400), //é uma classe concreta
new Aereo(2000,50) //é uma classe concreta
};
int n = sizeof(a) / sizeof(Veiculo*);
for (int i = 0; i < n; i++)
cout << *a[i] << a[i]->meioOndeSeDesloca();
delete a[0];
delete a[1];
}

………..polimorfismo, destrutores virtuais
O destrutor de uma classe base pode não ser suficiente para “destruir” um objecto de uma classe derivada
o uso delete, vai invocar o destrutor:
se o destrutor for virtual na classe do ponteiro, vai ser usado o destrutor de classe apontado
se o destrutor não for virtual na classe do ponteiro, vai ser usado o destrutor da classe ponteiro, que não é o destrutor da classe do objeto que está a ser destruído

na herança, o destrutor da classe derivada é executado mas depois chama o destrutor da base

p.e.:
class Veiculo {
int peso;
public:
Veiculo(int p = 0) : peso(p) {}
virtual ~Veiculo() { cout << “Destruindo Veiculo\n”; } //é virtual
};
class Aereo :public Veiculo {
int altura_voo;
string * historico;
int n;
public:
Aereo(int p = 0, int a = 0) : Veiculo(p), altura_voo(a), historico(nullptr), n(0) {}
virtual ~Aereo()override { //foi feito o override
delete[] historico;
cout << “Destruindo Aereo\n”;
}
};
int main() {
Veiculo* p = new Aereo(2000, 50);
// …
delete p; // funciona o destrutor de Aereo
// porque o destrutor foi declarado como virtual na classe Veiculo
}

………..polimorfismo, Colecção polimórfica e composição, duplicação polimórfica
existem agora elementos diferentes na colecção
(ver exemplo do aquário)
queremos fazer uma copia (duplicar), se fossem todos iguais eram com o new, mas neste caso temos elementos diferentes.
a solução:
duplicação polimorfica
na classe base é definida uma função virtual que duplica o objeto
mas não podem haver objectos da classe base, porque ela é a abstracta
nas classes derivadas é concretizada a função duplica, e esta função vai fazer o return new Derivada(*this) <-“é o construtor por cópia gerado automaticamente” a funcionar
e na classe base, surge na função de atribuição a duplicação dos objetos, recorrendo a Peixe* p = orig.peixes[i]->duplica();

p.e.:
class Peixe {
// …
};
class TetraPeixe : public Peixe { //classe derivada
// …
};
class NeonPeixe : public Peixe { //classe derivada
// …
};

class Aquario {
// o aquario contém uma colecção de peixes que podem ser de diversos tipos
vector<Peixe*> peixes; //vector de ponteiros para peixes, e pode ser cada um de sua classe, é um vector polimorfico
// …
public:
Aquario() = default;
// Os peixes são criados e destruídos no aquario
// A relação entre o aquário e os peixes é de composição
Aquario(const Aquario& orig); // construtor por copia
Aquario& operator=(const Aquario& orig); // operador atribuicao
virtual ~Aquario(); // destrutor
// …

// funcao abstracta, nao se podem criar objectos desta classe
virtual void alimentar(int quantidade, Aquario* aquario) = 0;
// duplicação polimórfica dos peixes
// como a classe é abstracta, esta função também tem que ser abstracta porque
// não se podem criar objectos da classse Peixe
virtual Peixe* duplica()const = 0; //duplicação polimórfica
};

Aquario::~Aquario() {
for (Peixe* p : peixes) {
delete p;
}
}

class TetraPeixe : public Peixe {
// …
public:
// …
// cria uma cópia de si mesmo em memória dinâmica
Peixe* duplica()const override;
};
Peixe* TetraPeixe::duplica()const { //garante a duplicação
return new TetraPeixe(*this);
}

class NeonPeixe : public Peixe {
// …
public:
// …
// cria uma cópia de si mesmo em memória dinâmica
Peixe* duplica()const override;
};
Peixe* NeonPeixe::duplica()const { //garante a duplicação
return new NeonPeixe(*this);
}

Aquario& Aquario::operator=(const Aquario& orig) { //operador atribuição
// prevencao da auto-atribuicao
if (this == &orig) {
return *this;
}
// libertar memoria dinamica do primeiro membro da atribuição
for (int i = 0; i < peixes.size(); i++) {
delete peixes[i];
}
//esvaziar o vector
peixes.clear();
// copiar a informacao de orig, duplicando os objectos dinamicos do tipo Peixe
for (int i = 0; i < orig.peixes.size(); i++) {
Peixe* p = orig.peixes[i]->duplica();
peixes.push_back(p);
}
// …
return *this;
}

Aquario::Aquario(const Aquario& orig) { //construtor por cópia
//funcionou o construtor por omissao do vector de ponteiros
//o vector está vazio
// não há ponteiros com valores indefinidos
*this = orig;
}

Tags : , , , , ,

POO, introdução II

………..Conversões de tipo primitivos
p.e.:
long l = 10;
int i = static_cast<int>(l);

………..Conversões de tipo de objectos das classes
de um tipo qualquer num objeto da nossa classe e é feito com construtores que aceitam um só argumento do tipo da origem quando é de um objecto da nossa classe num outro tipo são feitas com operadores de conversão e estas conversões podem ser implícitas ou explícitas.

p.e.:
conversão de um outro tipo num objecto da nossa classe
class Complexo {
double a; // parte real
double b; // coeficiente da parte imaginária
public:
// construtor que admite um argumento => conversão:
// argumento -> objecto da classe
Complexo(double aa = 0, double bb = 0);
Complexo & operator+=(const Complexo & x); //operador membro
// …
};
Complexo operator+(const Complexo & x, const Complexo & y);
ostream & operator<<(ostream & saida, const Complexo & x);
assim:
Complexo(double aa = 0, double bb = 0);
pode receber nenhum argumento
um argumento //-> esté o que interessa neste caso
ou dois argumentos

conversão implícita:
Complexo b = 2; // pois o que acontece é Complexo b = Complexo(2)
conversão explicita
a = b + Complexo(2); //

………..extra: operador + e – devem ser global, recomendado, são mais abrangentes
ERRO:
a = 4 + b ,
pois neste caso equivaleria a
a = 4.operator+( b).
sendo global:

………..Construtores e conversões , Construtores explicit
p.e.:
na classe String,
String(int n)
e é feito na iniclização:
String s = ‘a’; //estávamos a reservar bytes
então podemos ter um conversor com a palavra explicit ele só vai trabalhar quando quisermos
class String{
// …
String(const char * s); // construtor conversor, conversão implícita
explicit String ( int n); // construtor conversor, conversão explicita
};

………..operador de conversão
é uma função obrigatoriamente membro
tem o nome operator
tem o tipo de destino
não tem parâmetros
não tem tipo de retorno, pois retornar o tipo de destino
const não altera o objecto
p.e.:
class Relogio {
int hora; // 0 – 23
int minuto; // 0 – 59
int segundo; // 0 – 59
public:
Relogio( int hora = 0, int minuto = 0, int segundo = 0);
operator int( )const; //serve para converter em inteiro
//…
};
e o operator surgia como:
Relogio::operator int( )const{
return segundo+60*(minuto+60*hora);
}
eficiência:
int main( ){
Relogio t(2, 10, 5);
int s = static_cast<int>(t); // conversão explicita
cout << “\n Total de segundos: ” << s;
s = t; // conversão implícita
cout << “\n Total de segundos: ” << s;
}

assim as Conversões implícitas devem ser para:
argumento com que uma função é chamada para o tipo do correspondente parâmetro com que é definida;
valor de retorno de uma função para o tipo de retorno especificado no protótipo da função;
operandos em expressões;
inicializadores.

………..Operador e Opção recomendada
resumo:
operadores unários
funções membros

=()[] operadores de conversão
têm que ser funções membros

+= -= /= *= etc (observar a diferença de “estatuto” entre o 1º e o 2º operandos)
funções membros

outros operadores binários (operandos com “estatuto” análogo)
funções globais

operadores binários em que o 1º operando não pertence à classe em causa da classe em causa
não podem ser funções membros

(construtores por cópia, operador atribuição, .. )
………..composição
a associação (relacionamento de duas classes) de objectos pode ter duas formas:
ou agregação (ter, tem, agrega p.e.: classe A tem objecto classe B, sendo que os objectos da classe B existem sempre, mesmo que A seja destruída; p.e.: turma e alunos)
ou composição (tem mas, se a classe A uca objecto da classes B, se A desaparecer, B também desaparece)

composição vs agregação
p.e.:
existe um relação de composição
se o poema for destruído, os versos são destruídos
um objecto poema tem posso exclusiva dos seus versos
class Poema {
string titulo;
string * pVersos; // ponteiro para um array dinâmico de strings
int nVersos; // obrigatório se não for char *c: numero de elementos do array dinâmico
public:
Poema(const string & t);
~Poema(); // destrutor, para libertar antes
void acrescentaVerso(const string & verso);
void eliminaVerso(int ordem);
// . . .
string getAsString()const;
};

exame: não se pode usar vectores, para usar este tipo de notação

assim surge uma situação de a = b
a atribuição não pode funcionar por omissão, a solução é usar um operador atribuição, e desta forma tudo o que a atribuição faz vai ficar bloqueado
o operador atribuição vai surgir na classe
possibilitando que os objectos sejam fisicamente independentes
public:
Poema(const string & t);
void acrescentaVerso(const string & verso);
void eliminaVerso(int ordem);
Poema & operator=(const Poema & ob);//operador atribuição, operador membro
~Poema(); // destrutor
// . . .
string getAsString()const;
};

//operador atribuição a=b
Poema& Poema::operator=(const Poema& ob) { //é o A, e é o *this, sendo B o op
if (this == &ob) { // prevenção da auto-atribuição
return *this;
}
// se os membros da atribuição forem objetos diferentes
titulo = ob.titulo;
nVersos = ob.nVersos;
// libertar a memoria dinâmica usada exclusivamente pelo primeiro membro
delete[] pVersos;
pVersos = nullptr;
// se a origem da copia for um poema sem versos …
if (ob.pVersos == nullptr || ob.nVersos == 0) {
return *this;
}
// reservar memoria dinâmica para conter uma copia exclusiva dos versos do segundo membro
pVersos = new string[ob.nVersos]; //array dinamico, reserar espaço em memória
// fazer essa copia
for (int i = 0; i < ob.nVersos; ++i) {
pVersos[i] = ob.pVersos[i];
}
return *this;
}
mesmo que a classe não tenha o construtor por cópia, ela existe sempre pois é gerada automaticamente como a atribuição.
e constrói por cópia membro a membro
neste caso copiar o ponteiro pVersos, ficando todos a apontar para a mesma zona de memória

………..construtor por cópia
análogo à atribuição

p.e.:
na classe Poema surge o construtor por cópia
class Poema {
string titulo;
string* pVersos; // ponteiro para um array dinamico de strings
int nVersos; // numero de elementos do array dinamico
public:
Poema(const string& t);
void acrescentaVerso(const string& verso);
void eliminaVerso(int ordem);
Poema& operator=(const Poema & ob);//operador atribuicao, operador membro
Poema(const Poema & ob); //construtor por cópia
~Poema(); // destrutor
// . . .
string getAsString()const;
};

e a função vem:
Poema::Poema(const Poema& ob):titulo(ob.titulo), nVersos(ob.nVersos) {
// titulo e nVersos inicializados com os mesmos valores de ob
// se a origem da copia for um poema sem versos …
if (ob.pVersos == nullptr || ob.nVersos == 0) {
pVersos = nullptr;
return;
}
// reservar memoria dinamica para onde copiar os versos de ob
pVersos = new string[ob.nVersos];
// copiar o conteudo do array dinamico
for (int i = 0; i < nVersos; ++i) {
pVersos[i] = ob.pVersos[i];
}
}

o construtor por cópia funciona:
quando se cria um objecto por cópia de outro;
quando passamos um objecto por valor a uma função (surge um novo objecto);
quando uma função retorna um objecto por valor, sendo que o que sair no return é a cópia;
assim
O construtor por cópia tem usualmente a forma
EstaClasse::EstaClasse( const EstaClasse & ob)

as diferenças entre Construtor por cópia / operador atribuição:
operador atribuição tem a prevenção da auto-atribuicao, que não aparece no construtor por cópia;
no construtor por cópia não é preciso tratar da memória velha, pois o objecto está a ser criado;
e no construtor por cópia não tem os retornos;

assim sendo podíamos escrever o construtor por cópia em função do operador atribuição:
(fazer um à custa do outro)

Poema::Poema(const Poema & ob):pVersos(nullptr){ // preparar pVersos para ser operando de delete
// preparar o objeto que esta a ser criado para ser alvo do operador atribuicao
*this = ob; // aplicar o operador atribuicao: operator=(s)
}
Poema & Poema::operator=(const Poema & ob){
if (this == &ob) {// prevencao da auto-atribuição
return *this;
}
// se os dois membros da atribuicao forem objetos diferentes
titulo = ob.titulo;
nVersos = ob.nVersos;
// libertar a memoria dinamica usada exclusivamente pelo primeiro membro
delete[] pVersos;
pVersos = nullptr;
// etc.
// . . .
}

void Poema::acrescentaVerso(const string & verso){
// reserva espaço para mais um
string * aux = new string[nVersos + 1];
// copia os versos existentes
for (int i = 0; i < nVersos; ++i) {
aux[i] = pVersos[i];
}
// o novo verso está em último lugar
aux[nVersos] = verso;
++nVersos; // incrementa o número de versos
delete[] pVersos; // liberta array dinâmico anterior
// pVersos aponta para o novo array dinamico
pVersos = aux;
}

void Poema::eliminaVerso(int ordem) {
if (ordem < 0 || ordem >= nVersos){ return; } //fora dos limites
if (nVersos == 1) {// se retirar o ultimo
delete[] pVersos;
pVersos = nullptr;
nVersos = 0;
return;
}
// reserva espaço ajustado para menos um
string * aux = new string[nVersos – 1]; //nao for o ultimo, aloco novo espaço
// copia os versos anteriores ao verso a eliminar
for (int i = 0; i < ordem; ++i) {
aux[i] = pVersos[i];
}
// copia os versos posteriores ao verso a eliminar
for (int i = ordem; i < nVersos – 1; ++i) {
aux[i] = pVersos[i + 1];
}
–nVersos; // decrementa o número de versos
delete[] pVersos; // liberta array dinâmico anterior
pVersos = aux; // pVersos aponta para o novo array dinamico
}

………..composição de objectos
um objecto dentro de outro objecto
quando o objecto for criado, antes funcionam todos os construtores dos sub-objectos. funcionam porque nos especificamos ou então é por omissao.
p.e.:
class String {
char* p;
void setString(const char * s);
public:
String(); // construtor por defeito
String(const char * s); // construtor conversor
String(const String & s); // construtor por copia
~String(); // destrutor

const char* getString()const;
ostream & imprime(ostream & saida)const;
String & operator=(const String & x); // operador atribuicao
String & operator+=(const String & x);

static int strTam(const char * s);
};
String::String() {
p = 0;
cout << “Constr. string nula” << endl;
}

String::String(const char * s) {
setString(s);
cout << “Constr. string ” << (p ? p : “nula”) << endl;
}

String::String(const String & s) {
setString(s.p);
cout << “Constr. por copia string ” << (p ? p : “nula”) << endl;
}

String::~String() {
cout << “Destr. string ” << (p ? p : “nula”) << endl;
delete[] p;
}

void String::setString(const char * s) {
int t = strTam(s);
if (!t) {
p = 0;
return;
}
p = new char[t + 1];
if (!p) {
cout << “\nMemoria insuficiente”;
return;
}
strcpy_s(p, 5 ,s);
}

const char* String::getString()const { return p; }

ostream& String::imprime(ostream & saida) const {
if (p) saida << ” ” << p;
else saida << ” String nula”;
return saida;
}

String& String::operator=(const String & x) {
if (this != &x) {
delete[] p;
setString(x.p);
}
cout << “Oper. atrib. string ” << (p ? p : “nula”) << endl;
return *this;
}
String& String::operator+=(const String & x) {
char * aux = new char[strTam(p) + strTam(x.p) + 1];
if (!aux) {
cout << “\nMemoria insuficiente”;
return *this;
}
if (p) strcpy(aux, p);
if (x.p) strcpy(aux + strTam(p), x.p);
delete[] p;
p = aux;
return *this;
}
int String::strTam(const char * s) {
return (s ? strlen(s) : 0);
}
ostream& operator<<(ostream & saida, const String & x) {
return x.imprime(saida);
}

class Data {
int dia;
int mes;
int ano;
public:
Data(int d = 1, int m = 1, int a = 2000);
~Data();
int getDia() const;
int getMes() const;
int getAno() const;
void setDia(int d);
void setMes(int m);
void setAno(int a);
void anosDepois(int n);
};
Data::Data(int d, int m, int a) {
cout << “Constr. data ” << d << “/” << m << “/” << a << endl;
dia = d; mes = m; ano = a;
}
Data::~Data() {
cout << “Destr. data ” << dia << “/” << mes << “/” << ano << endl;
}
int Data::getDia() const { return dia; }
int Data::getMes() const { return mes; }
int Data::getAno() const { return ano; }
void Data::setDia(int d) { dia = d; }
void Data::setMes(int m) { mes = m; }
void Data::setAno(int a) { ano = a; }
void Data::anosDepois(int n) { ano += n; }

class Pessoa {
String nome;
String endereco;
String telefone;
Data nascimento;
public:
Pessoa(const char* n, const char* end, const char* tel, int d, int m, int a);
Pessoa(const char* n);
~Pessoa();
int getAnoNascimento()const;
};

Pessoa::~Pessoa() {
cout << “Fim\n”;
}

Pessoa::Pessoa(const char * n, const char * end, const char * tel, int d, int m, int a) : nome(n), endereco(end), telefone(tel), nascimento(d, m, a) {
cout << “Inicio\n”;
}

Pessoa::Pessoa(const char* n) : nome(n) {
cout << “Inicio\n”;
}

int Pessoa::getAnoNascimento()const {
return nascimento.getAno();
}

int main() {
Pessoa a(“Pedro Sousa”, “Rua do La Vai Um, 1, Coimbra”, “11111”, 1, 11, 1980);
Pessoa b(“Teresa Oliveira”);
cout << “Pedro Sousa nasceu em ” << a.getAnoNascimento() << endl;
cout << “Teresa Oliveira nasceu em “<< b.getAnoNascimento() << endl;
Pessoa c = a; // construção por cópia
c = a; // atribuição

}

Tags : , , , , ,

PIXEL: Concurso europeu

Está a decorrer um concurso Europeu, sobre a sigla “9th edition of Poland’s largest indie gamedev competition”, e com as seguintes categorias:
Big Fish Grand Prix
Indie Grand Prix
Best Gameplay
Best Art
Best Audio
Warsaw Excellence
Festival Audience Special Award
Best Audio
Best Story
Retro Roots
Big Bang!
Best Student
Total Blackout (best board game)

As regras são simples, e uma das referências é que não podem ser jogos que foram publicados antes de 31/dez/2020 não podem entrar a concurso. O prazo de submissão termina no próximo dia 17/setembro.

+infos(oficial): LINK

Tags : ,

Proposta de trabalho (em Bradford, UK)

Não pretendo publicar aqui anúncios “avulso” que surgem pelo mundo relacionados com o mundo dos videojogos, gosto de ir observando e analisando as propostas que vão sendo publicas e sobre empresas portuguesas ou então que estão com escritórios em Portugal.

Mas este é diferente, achei a proposta de trabalho muito interessante:
“Job description
Do you have a broad knowledge of gaming and gaming history or culture? Do you have experience of communicating history and STEM topics to non-specialist audiences?

Collectively gaming development and gaming technologies are the UK’s largest creative industry. The Science Museum Group (SMG) is developing a group-wide public programme to celebrate gaming and gaming culture and wants to fully explore how this media can help engage our visitors and non-visitors with STEM.

To help lead this work, we are now recruiting for a Curator of Game Technologies to be based at our National Science & Media Museum (NSMM) in Bradford (but with some travel to other sites). In this role, you will play a critical role in the development and support of the season of gaming across SMG, including group-wide exhibitions on gaming, events and programming including on site and digital elements, between 2023 and 2024, whilst also leading on collections research and development in this emergent area helping SMG to understand how this area fits strategically within the group. As Curator of Game Technologies you will work with colleagues across SMG to explore the history, development and use of gaming technologies. This role will explore how SMG defines and collects in this area and will seek to engage visitors through our collections, public exhibition programme, festivals and events.

Joining us, you will have broad knowledge of gaming and gaming history/culture. You will hold strong research skills; you’ll be able to find interesting stories related to our collection and will be able to communicate these to non-specialist audiences through exhibitions, articles, blogs, outreach or teaching. You’ll be able to bring stakeholders together and lead collaborative working and will be proactive and organised in your approach to work.

The Science Museum Group (SMG) is here to inspire futures. As the world’s leading group of science museums, we share our unparalleled collection spanning science, technology, engineering, mathematics and medicine with over five million visitors each year. Joining us as an employee, you will have the opportunity to develop your career in a world-class museum group. We know work/life balance and wellbeing is crucial to our colleagues, so we currently offer up to 25 days annual leave in addition to bank holidays; BUPA medical and dental care; employee assistance programme; enhanced contributory pension; enhanced occupational sick, maternity, paternity and adoption leave and career breaks.

‘Open for All’ is one of the Science Museum Group’s five core values and sets out our important aspiration to be a place for everyone. As a national museum group, we have an ability to reach a wide and diverse population of audiences, colleagues and partners through our geography and scale.

We are working hard to understand our organisation better and to foster a culture that recognises and values different backgrounds, mindsets, skills, experience, knowledge and expertise. By having greater diversity, we believe that we will be a stronger and better organisation and ultimately will be able to inspire more futures. We therefore welcome applications from those who bring difference.”

+infos(oficial): LINK

Tags :

Retromagazine World, uma revista

A Retromagazine World é uma revista online acerca do mundo retro dos videojogos. Originalmente é em italiano mas também tem uma edição em inglês que recomendo a leitura. É possivel descarregar os PDFs sem qualquer custo

+infos(a revista): LINK

Tags :

Um português que trabalha no mundos dos videojogos

Encontrei esta entrevista de mais um português que tem desenvolvido o seu trabalho também na área dos videojogos, neste caso mais especificamente na construção de musicas.

“Fans of certain beloved Sega franchises should be very familiar with this composer’s name by now. Tee Lopes started out on the VGM scene releasing remixed and reimagined versions of some of gaming’s most beloved music, with a special focus on one blue hedgehog in particular, and his compositions and arrangements now sit alongside those of series legends such as Masato Nakamura, Jun Senoue and Yuzo Koshiro in the Sonic canon.
His talent and passion garnered the attention of the right people over the last decade, and in recent years he’s supplied the soundtrack for the brilliant Sonic Mania (a game that’s now four-years-old!) as well as the Mr. X Nightmare DLC for Streets of Rage 4, and his work will also be heard in the upcoming Teenage Mutant Ninja Turtles: Shredder’s Revenge and Metal Slug Tactics. If you’ve got a retro revival in the works and want to capture the spirit of a treasured series while also taking the audio to new and exciting places, it seems Tee Lopes is your go-to composer.
We kick off the Nintendo Life Video Game Music Fest — a season of VGM-focused features and interviews — with an email chat with Tee where we asked him about how he started out, how he goes about crafting new music for retro-inspired titles, and his first experience with the Sonic series…
(…)
I come from a small town in Portugal, and growing up, my access to music was very limited. We only had four TV channels and a local radio station, which mostly played whatever was popular at the time, and there wasn’t a music store for miles. Because of this, video games were like a dimensional portal that allowed me to discover music I wouldn’t have heard anywhere else. Especially Japanese music, which I immediately identified with.
My list of influences is long, but I’ll mention a few names: Jun Senoue, Michiru Yamane, Nobuo Uematsu, Harumi Fujita, Takenobu Mitsuyoshi, Yuzo Koshiro, Shusaku Uchiyama, and many others. I can’t say my tastes have changed (and I’ve put that to the test), but they’ve certainly evolved and expanded. A lot of the stuff I find interesting nowadays probably would’ve sounded too odd to me some years ago.
(…)”

+infos(fonte): LINK

Tags : , ,

POO, introdução IV

………..enumerações
enum class Letras {a,b,c,d,e};
para se usar ou atribuir
Letras x = Letras::A;
x = Letras::C;
if (x == Letras::C) cout << ” x == C \n”;

………..conversões explicitas
para Conversões implícitas
double d = 0.0;
int x = static_cast<int>(d); // Mais explícita

………..Excepções
O tratamento de exceções geralmente é usado quando uma parte de um programa detecta um problema (excepção) que não pode resolver e …
ou precisa de uma maneira de sinalizar que algo aconteceu e que não pode continuar;
ou depois de sinalizar a condição excepcional, pára o processamento.

assim:
a instrução throw que a parte de um programa que detecta a excepção utiliza para lançar a excepção – sinalizar a situação que não consegue resolver
blocos try e cláusulas catch – as excepções lançadas do código executado dentro de um bloco try geralmente são tratadas por uma das cláusulas catch.

em que:
quando é lançado um throw o bloco de código fica interrompido (será lançada e não é tratada)
mas pode ser usado algo similar ao seguinte:
try {
// …
// Código que pode gerar excepções
// …
} catch( Erro1 e1 ) {
// Trata excepções do tipo Erro1
} catch( Erro2 e2 ) {
// Trata excepções do tipo Erro2
} catch( Erro3 e3 ) {
// Etc…
} catch( ErroN eN ){
// Trata excepções do tipo ErroN
}
// Continua a execução “normal”…
se existir pelo menos uma cláusula catch que possa corresponder ao tipo da excepção lançada
se não existir nenhuma cláusula catch que possa corresponder ao tipo da excepção lançada, a situação de erro continua
quando temos um try:
no throw nome(), nome() siginfica para procurar um catch com esse nome()
o catch (…), significa qualquer outro erro que não seja dos contemplados

p.e.:
class Excep {
public:
string what()const { return string(“Excep\n”); }
};
class A {
public:
A() { cout << “Construtor de A\n”; }
~A() { cout << “Destrutor de A\n”; }
};
void f() {
A obF;
cout << “–>f: antes de lancar a excepcao\n”;
throw Excep();
cout << “–>f: depois de lancar a excepcao\n”;
}
int main() {
try {
cout << “main:antes de chamar f()\n”;
f();
cout << “main:depois de chamar f()\n”;
}
catch (Excep & ex) { //é criado menos um objecto, porque a passagem é por referência
cout << ex.what();
}
cout << “main:depois de tratar a excepcao\n”;
}

Para relançar uma excepção capturada numa cláusula catch, utiliza-se a instrução throw sem argumentos. As cláusulas catch seguintes (correspondendo ao mesmo bloco try) são ultrapassadas apesar deste relançamento, sendo a excepção remetida para o próximo contexto envolvente.
Mesmo com o relançamento de uma excepção, nunca é executada mais do que uma cláusula catch de entre as que correspondem a um mesmo bloco try.
p.e.:
throw;

p.e.:
class Avaria {
string mensagem;
public:
Avaria(const char* msg = “”) :mensagem(msg) {}
string what() const { return mensagem; }
};
class AvariaLigeira : public Avaria {
public:
AvariaLigeira() : Avaria(“Avaria ligeira:\n”) {}
};
class AvariaGrave : public Avaria {
public:
AvariaGrave() : Avaria(“Avaria grave:\n”) {}
};
void assistenciaEmViagem(int avaria) {
try {
cout << “\n…assistencia em viagem…\n”;
switch (avaria) {
case 0: cout << “tudo em ordem!\n”;
break;
case 1: throw AvariaLigeira();
break;
case 2: throw AvariaGrave();
break;
}
}
catch (AvariaLigeira & e) {
cout << e.what() << “…resolvida no local\n”;
}
catch (AvariaGrave & e) {
cout << e.what() << “…rebocar para a oficina\n”;
throw; //relançar a excepção
}
cout << “…fim de etapa!\n”;
}

int main() {
try {
assistenciaEmViagem(0);
assistenciaEmViagem(1);
assistenciaEmViagem(2); //chamada à função que termina em erro
assistenciaEmViagem(0);
}
catch (AvariaGrave& e) {
cout << “\nmain()-> ” << e.what() << ” -> Avaria reparada na oficina\n” << ” -> canceladas etapas seguintes\n”;
}
}

………..Smart pointers
Permitem gerir de forma mais fácil e segura objectos em memória dinâmica.
Encapsulam ponteiros de tipo primitivo.

tres tipos:
unique_ptr (posso exclusiva do objecto apontado)
shared_ptr (objectos apontados por mais do que um ponteiro)
weak_ptr ()

exemplo de unique_ptr:
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <regex>
#include <initializer_list>
#include <fstream>

using namespace std;

class Produto
{
string nome;
int preco;
public:

Produto(string nome0, const int preco0)
: nome(nome0),
preco(preco0)
{
cout << ” construtor ” << getAsString() << endl;
}
~Produto()
{
cout << ” destrutor ” << getAsString() << endl;
}
string getAsString() const
{
ostringstream oss;
oss << nome + ” preco: ” + to_string(preco);
return oss.str();
}
};

int main()
{
//smart pointer
unique_ptr<Produto> prod = make_unique<Produto>(“Arroz”,1);
//make_unique cria o objecto em mem dinamica
//make_unique cria o smart_pointer na stack
cout << prod->getAsString();

//versao2, dá erro porque não tem construtor por cópia nem atribuir
//unique_ptr<Produto> prod2 = make_unique<Produto>(“Maria”, 22);
//unique_ptr<Produto> prod3(prod2);
//cout << prod2->getAsString();

cout << “\nfim do main” << endl;
}

mas o unique_ptr Não dispõe de:
Construtor por cópia
Operador atribuição

o unique_ptr pode ser movido mas não copiado, existe um construtor move

exemplo de unique_ptr semantica move:
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <regex>
#include <initializer_list>
#include <fstream>

using namespace std;

class Produto
{
string nome;
int preco;
public:

Produto(string nome0, const int preco0)
: nome(nome0),
preco(preco0)
{
cout << ” construtor ” << getAsString() << endl;
}
~Produto()
{
cout << ” destrutor ” << getAsString() << endl;
}
string getAsString() const
{
ostringstream oss;
oss << nome + ” preco: ” + to_string(preco);
return oss.str();
}
};

unique_ptr<Produto> cria_Produto() {
unique_ptr<Produto> local_ptr = make_unique<Produto>(“Bolachas”, 2);
return local_ptr; // local_ptr entrega a posse do objecto
}
void f() {
cout << “constr move:\n”;
unique_ptr<Produto> p1(cria_Produto()); // constructor move,
// recebe um objeto retornado por valor, um rvalue
// p1 tem agora a posse do objecto
cout << “atribuicao move:\n”;
unique_ptr<Produto> p2; // constructor por omissão, p2 não possui nada
p2 = cria_Produto(); // atribuição move
// o segundo membro da atribuicao é um objeto retornado por valor, um rvalue
// p2 tem agora a posse do objecto, o segundo objecto criado
}

int main()
{
unique_ptr<Produto> a = make_unique<Produto>(“Cafe”, 2); // a possui um objecto Produto
unique_ptr<Produto> b; // b não possui nada
// invocar atribuição move explicitamente
b = std::move(a); // move retorna uma referência rvalue para a
// funciona o operador atribuição move
// agora b possui o objecto Produto, a não possui nada
// invocar construção move explicitamente
unique_ptr<Produto> c(std::move(b)); // move retorna uma referência rvalue para b
cout << b->getAsString();

cout << “\nfim do main” << endl;
}

Tags : , , , , ,

Humble Software Bundle: unity fantasy games & game dev assets (uma campanha)

Uma campanha na plataforma Humble.. com vários assets para serem usados no Unity. Da lista de prendas desta campanha consta:
Odin Inspector and Serializer
Bakery
RPG Builder
The Minute of Islands
Waking
Zenva Unity Course – Online Unity Course
Octave3D-Level Design
Node Canvas
Dreamteck Splines
Nature Packages – Forest Environment
Brute Force – Grass Shader
Editor Console Pro
Mountain Trees – Dynamic Nature
Dark Fantasy Gigantic Environment
Fantasy Adventure Environment
FPS Medieval Weapons – Ultimate Pack
The Big Castle Kit
uMMORPG
Fantasy Sounds Bundle
GUI PRO Kit – Fantasy RPG
Mobile Tools + Complete Game
InfiniCLOUD
FurryS2: Sorceres and Archer
RPG Fantasy (Pack)
Low Poly Tools Bundle
Dark Fantasy Kit
Fantasy Ambience Sounds Pack
Medieval Houses Modular Vol 1

+infos(a campanha): LINK

Tags : , , , , , , ,

Proposta de trabalho (em Lisboa)

Encontrei esta proposta de trabalho..

“A Infinity Games é um publisher e developer dedicada ao desenvolvimento de jogos para Android e iOS. Procuras desenvolver jogos em Unity e gostarias de trabalhar numa empresa portuguesa, com um ambiente de trabalho descontraído, um forte espírito de equipa e que a cada segundo que passa tem dezenas de milhar de jogadores colados nos seus jogos?

Skills necessárias:
Domínio Sénior de Unity em ambiente 2D/3D;
Domínio Sénior de C# e Javascript;
Bons conhecimentos de Álgebra e Cálculo;
Domínio absoluto de Inglês, tanto oral como escrito.

Skills valorizadas:
Experiência com o Desenvolvimento de Puzzles;
Experiência com Shaders
Familiaridade com XCode e Android Studio;
Experiência com integração de Third-Party SDKs;
Capacidades de problem-solving e dedução;
Boa comunicação e espírito de equipa.

O que irás fazer e o que esperamos de ti:
Desenvolvimento de novos jogos dentro da plataforma Unity para iOS e Android;
Criação de novas funcionalidades em jogos já existentes;
Implementação de SDK’s de anúncios, atribuição e outros;

Para te candidatares a esta vaga, envia a tua carta de apresentação e CV com a referência “unity-relax” para support@infinitygames.io”

+infos(oficial): LINK

Tags :

Proposta de trabalho (em Lisboa)

Senior Game Designer
“Miniclip is looking for a Senior Game Designer to hire in our Lisbon (Portugal) Games Development Studio. This is a full-time position.
This is a fantastic opportunity to develop your free-to-play design career in mobile help bring new titles to market, and work on highly successful live games at a leading mobile studio that’s just 10 minutes from the beach!
Duties
Your Primary Responsibilities Will Include
Work with the team to design and craft gameplay experiences and game features that deliver strong player engagement, virality, retention, and monetisation.
Work with the team to create and craft game content to delight players, and devise & balance meta-game economies to maximise game performance.
Write, review and give feedback on game/feature design documents, builds, and game roadmap plans.
Participate as a key member of the product team across the product life-cycle, working on new titles, games in production, and live titles, proposing high-impact updates to our existing portfolio of games.
Help identify and deconstruct new markets and opportunities, expanding the portfolio of the company and staying in the cutting edge of the mobile gaming industry.
Collaborate with other designers to improve overall output, and support the team in growing & developing their design capabilities.
Assist with reviewing, scheduling & prioritising design team workload.

Skills & Experience
We are looking for a social, hard-working person who enjoys working in a team, and is passionate about games, and mobile free-to-play. The ideal candidate will be articulate, proactive & energetic, with the following attributes
Significant experience designing successful free-to-play published titles, preferably on mobile.
Experience across the product life cycle, from prototyping, through production, to updating a live free-to-play game.
Strong knowledge of the mobile & social game space, with exceptional understanding of current design techniques to deliver excellent engagement, retention, and monetisation.
Highly numerate, with experience designing virtual currencies and managing in-game economies.
Experience with reviewing game analytics, designing AB tests, and producing insights based on data to make better informed design decisions.
Strong grasp of mobile user-experience design, and ability to consider & empathise with many different types of players.
Mature judgment, able to balance between innovation and setting reasonable goals.
Collaborative & effective communicator, with an ability to work with multinational teams, with a variety of cultural backgrounds.
A hard worker, with drive, initiative, and ability to self-manage effectively.
Highly organised, with a track-record of guiding & advising others (some management experience is ideal).
Ability to compromise and prioritise appropriately to deliver to tight deadlines.
Additional Information

You will be working in our fashionable, open plan studio in Lisbon with enthusiasts and professionals from the games industry. We like to maintain a very friendly and relaxed atmosphere, with regular team building and social events. We understand that being tied to a desk all day is not fun and that’s why there is a games area and fridge with complimentary drinks and fruit for all staff.”

+infos(oficial): LINK

Tags :

12 minutes um videojogo por Luís Amado

Já há algum tempo que tenho acompanhado este projeto que há umas semanas saiu para o mercado o videojogo “12 minutes” que é da responsabilidade de um português de nome Luís Amado. É um videojogo indie que teve chegou aos mundos dos grandes, consola Xbox e na Steam.

Este é o texto de um entrevista feita por Rui Pereira:

“Existem muitos portugueses talentosos ligados à indústria dos videojogos espalhados pelo mundo, em alguns dos estúdios mais conceituados. Mas o percurso de Luís António coloca-o entre os mais experientes. Depois de terminar o seu curso na Faculdade de Belas Artes não encontrou em Portugal oportunidades para entrar na indústria dos videojogos e partiu para o estrangeiro à procura do seu sonho. Passaram-se quase 20 anos desde então, e no seu currículo consta a passagem por editoras como a Rockstar Games e a Ubisoft (de artista principal a diretor de arte), estando envolvido em jogos como capítulos de Grand Theft Auto, Manhunt 2 e outros.
Depois de construir um currículo ligado a jogos AAA, Luís António abraçou a indústria indie e foi trabalhar com Jonathan Blow na produção de The Witness. Mas o sonho do designer português era lançar o seu próprio jogo, e desde há muitos anos que vem trabalhando num projeto pessoal, em forma de hobby, até chamar a atenção da imprensa internacional e um contrato com a Annapurna Interactive. Twelve Minutes está na cabeça de Luís António há mais de 10 anos e prepara-se para ser lançado no PC e Xbox no próximo dia 19 de agosto.

O produtor português contou como foi a sua jornada no desenvolvimento do seu primeiro jogo, as ideias e inspirações, e as dificuldades encontradas no seu percurso e a contratação de nomes sonantes de Hollywood para dar vida às suas personagens. Mas deixa uma certeza: se Twelve Minutes tiver sucesso, ao ponto de poder financiar o seu próximo jogo, o designer pretende regressar a Portugal para criar o seu próprio estúdio e dar o seu contributo à indústria de videojogos nacional.

Relembrando as origens de Twelve Minutes, Luís António refere que “já tenho a ideia há algum tempo para fazer um jogo baseado em “time loops”, a experiência de acumulação de conhecimento e fazer um jogo sobre o assunto. Quando trabalhei em outros estúdios tentei arranjar pessoas para trabalhar comigo, sobretudo no tempo livre, mas ninguém estava interessado”.

O projeto foi sendo cozinhado na sua cabeça durante anos, mas depois que se mudou para a Califórnia e começou a trabalhar no The Witness com o Jonathan Blow, abriram-se os horizontes da sua produção. “Conheci uma comunidade de developers que aprendem a programar e fazem os seus próprios jogos. E comecei a programar e a fazer um protótipo no tempo livre, que foi crescendo”. A partir daí foi um processo muito gradual, sem grandes saltos diretos, começando por procurar financiamento para continuar a seu trabalho a tempo inteiro.

Sobre o financiamento, Luís António diz que é um processo que dá trabalho, pois não tinha ideias iniciais de se dedicar a Twelve Minutes. Começou a fazer o protótipo enquanto trabalhava em full time no The Witness, e o plano era acabar o jogo e começar logo outro de seguida. Encarou o financiamento como algo descomprometido: se alguma editora estivesse interessada em financiar o jogo, este seguiria em frente, caso contrário não o faria, e continuaria como estava. “Falei durante um ano com muitas editoras, desde a Nintendo, PlayStation, Microsoft, mas tinha de ser alguém que me desse a liberdade e o controlo criativo”.

O português salienta que o seu ex-patrão Jonhatan Blow lhe deu bastante apoio, recebendo feedback para melhorar o protótipo. “Em 2015 eu tinha o protótipo pronto para experimentar, fui à Pax East, em Boston, e obtive um grande feedback dos jornalistas de sites internacionais de renome e do público em geral”. A partir daí as editoras começaram a mostrar mais interesse. “O Jonhatan Blow ajudou-me a garantir que eu não assinava nada até ter um jogo com os problemas de design resolvidos”. Luís António explicando que, por norma, quando se assina com a primeira editora que aparece, e depois surgem mais coisas no jogo, mudanças nos níveis ou outros problemas, a pressão do tempo e do dinheiro investido tornam a produção mais complicada. “Recebi muita ajuda, devido à minha falta de experiência, para não cair em nenhuma armadilha”.

Questionado sob a ideia e há quanto tempo está a trabalhar em Twelve Minutes, Luís António refere que a ideia em si, o “time loop” está a ser cozinhado há 10/15 anos, ainda estava na Rockstar Games. “Estávamos a acabar o Manhunt 2 e íamos começar outro jogo. Tínhamos a oportunidade de fazer um novo título original, e estávamos a discutir os projetos. E todos podiam fazer um “pitch” com ideias. Como tínhamos o motor de Grand Theft Auto, uma cidade inteira simulada, propus uma ideia de alguém estar a viver um “time loop”.

A sua proposta foi rejeitada, algo que aconteceu depois também na Ubisoft, embora a sua ideia tivesse sido reduzida, mais próxima da escala do atual do conceito de Twelve Minutes. “Apenas comecei a explorar mais profundamente o conceito quando me mudei para a Califórnia”. Quanto mais trabalhava no conceito, mas o jogo ficava reduzido em termos de espaço, “porque é impossível seguir os acontecimentos em loop numa cidade, pela complexidade de opções”.

O conceito de “time loop” já foi aplicado em outros videojogos como Legend of Zelda: Majora’s Mask e Outer Wilds, assim como em filmes como o Dia da Marmota (Groundhog Day) com Bill Murray, Edge of Tomorrow com Tom Cruise ou Memento de Christopher Nolan. Apesar dos filmes referidos terem sido inspiração para Twelve Minutes, nos videojogos o designer português foi buscar aos clássicos antigos, como Prince of Persia e Alone in the Dark, pelo seu tom cinematográfico. Nunca se sabe o que se está a passar e a personagem tenta descobrir. “No Prince of Persia morre-se e volta-se ao início do nível. Se tu e a personagem estiverem em sintonia, se esta tiver noção que está a repetir o nível mais uma vez, o que iria acontecer? Não é só o jogador que sabe que está a repetir o nível mais uma vez, mas também a personagem”.

Explicando o conceito da aventura, o jogo tem um ciclo em que o jogador controla o homem que chega a casa no fim do dia e é recebido pela esposa que preparou uma surpresa especial. Depois de começarem o seu serão, aparece um polícia que bate à porta, acusando a mulher de matar o seu pai. Desencadeia-se uma luta, o jogador leva um murro e desmaia e acorda novamente ao início do dia. “O jogador tem de utilizar o conhecimento prévio para quebrar esse time loop e sair da situação onde se encontra. O jogo passa-se todo num apartamento e é em tempo real, com apenas três personagens durante toda a trama”.

Luís António refere que a escolha de Twelve Minutes para o título aconteceu quando foi à Pax East, e ainda sem nome definido chamava-lhe Canadrum. “Quando vi que o loop demorava pouco mais de Twelve minutos, acabei por o batizar assim”. E o que acontece se o jogador deixar os controlos, o que acontece? “O polícia chega sempre ao fim de três ou quatro minutos em cada loop. O que acontece, caso não toquem nos controlos, é que o polícia chega e ataca e o loop é reiniciado. Ficas num loop constante de quatro ou cinco minutos. Para chegar ao fim dos 12 minutos tem de se resolver, pelo menos, que o polícia não ataque”.

O produtor português esteve a trabalhar sozinho no projeto durante três ou quatro anos, mas quando arranjou a editora, contratou freelancers para fazer as personagens, o apartamento, as animações e outros detalhes. “O projeto tem crescido e diminuído em número de pessoas consoante a fase em que está. Quando fizemos gravações com os atores de motion capture tivemos acesso ao estúdio, à equipa toda, os atores”. Explica que neste momento, até ao lançamento, tem uma equipa de Q&A a jogar extensivamente à procura de bugs, que depois tem de corrigir. Diz que também tem uma equipa de localização, outra para os controlos e adaptação do gamepad e de certificação para a consola.

Apesar dos planos iniciais serem PC e Xbox, outras versões do jogo para a Switch e PlayStation não estão fora dos seus planos. “Se o jogo for um falhanço total e ninguém gostar da experiência, não sei se iremos fazer para outras consolas. Por outro lado, se houver interesse, vamos analisar e ver”.

Twelve Minutes pretende ser acessível a todos
A aventura é jogada com o rato, num sistema point & click, e isso tem um propósito. “cresci com o The Secret of Monkey Island, Day of Tentacle e jogos da Lucas Arts. Sempre gostei de jogar com uma chávena de chá numa mão e o rato na outra, a fazer ações, sem a tensão constante de controlar a personagem e disparar. O Time Loop em si já é stressante, pois a pressão do tempo não é divertida. Por outro lado, este tipo de interface permite diversas ações diferentes, combinar coisas e ter resultados variados.”

O autor diz que queria que o jogo fosse mais acessível, dando o exemplo da esposa e vários amigos que não jogam jogos, sendo o maior problema controlar um gamepad ou segurar o rato e teclado. “Queria que o jogo fosse acessível a toda a gente e point & click funciona muito bem”. O jogo tem uma longevidade entre as 10 e 12 horas, dependendo da experiência dos jogadores em resolver puzzles. “A conclusão não é linear como um filme, mas há um momento em que os jogadores vão sentir que acabaram o jogo, com diversas variações”.

Uma das surpresas de Twelve Minutes foi a contratação de três atores de renome em Hollywood para encarnar as personagens do jogo: Willem Dafoe, Daisy Ridley e James McAvoy. Questionado sobre como surgiu o envolvimento dos atores e a sua contribuição para a narrativa, Luís António salienta que foi uma grande ajuda na credibilidade e marketing do jogo, mas também o enriquecimento das personagens. “O jogo gira à volta destas três personagens, e fazer os jogadores acreditarem nas suas motivações, e nas intenções que têm e as reações ao comportamento. E ter estes atores a interpretar as personagens e os diálogos ajudam a acreditar o que está a acontecer e a ficar mais intenso”.

Mas o plano inicial nem era o jogo oferecer vozes, apenas balões com as linhas de texto. Apenas surgiu a ideia quando o projeto começou a crescer e depois de ter obtido financiamento. A sua parceria com a Anapurma Interactive abriu-lhe portas à componente mais cinematográfica que caracteriza a editora. Primeiro arranjou-se talento local em Los Angeles para fazer uma “table read” para simular as vozes das personagens. “Vimos que a nuance do interesse pelas personagens aumenta. Investigámos se conseguíamos arranjar talento para mostrar que se trata de uma experiência séria e interativa, e trazer esse lado cinematográfico para o jogo”.

Depois foi iniciado o processo de escolher os atores que melhor se enquadrassem no papel das suas três personagens. “O processo de gravar para jogos não é algo fácil: passaram um mês a gravar sempre as mesmas linhas como “vamos comer o jantar, mas tiraste a faca; vamos comer o jantar mais fizeste isto”. É necessário estar confortável com esta repetição constante”.

Toda a história do jogo passa-se num apartamento, através de uma perspetiva aérea. Mas não se vai tornar repetitivo para o jogador? Luís António diz que essa é a questão inicial antes de se jogar Twelve Minutes. “Mas num jogo onde controlas o que se altera é muito importante ter uma estabilidade que possas controlar. Existe um prazer em saber que certas coisas não se alteraram. Por exemplo, o polícia chega e ataca-te, desmaias e acordas. Depois pensas, que podes trancar a porta ou esconder na casa de banho”. O designer explica que saber que as coisas são constantes e que as variáveis do conhecimento aumentam a cada loop, abrem-se possibilidades de coisas que se podem fazer e experimentar, sem que os jogadores fiquem perdidos nas suas possibilidades.

Para Luís António, aquilo que representa a grande mudança é na personagem principal, pois tudo o que o jogador faz tem impacto no mesmo, e ele reage a isso. E o progresso é o seu comportamento.

O mediatismo nacional e internacional
Desde que começou a ser mostrado nos eventos da Xbox, Twelve Minutes ganhou reconhecimento tanto ao nível nacional, como internacional. Mas terá esse mediatismo alterado o seu desenvolvimento? “Se dividisse o jogo em capítulos, diria que o capítulo final mudou bastante. O que aconteceu foi que havia esta ideia original, começou a ser expandida e quando os atores chegaram houve esta humanidade que foi dada às personagens, é que nos apercebemos que mudou muito a situação”.

Neste momento o designer tem alguns amigos developers a jogar e a enviar feedback que vai ser implementado ou corrigido no jogo. “Estes últimos dois anos foram essencialmente para polir a experiência, para que flua de forma mais natural”. Ao ser o designer e programador do jogo, Luís António diz que consegue fazer as alterações necessárias rapidamente.

Luís António diz que não estava à espera que o jogo tivesse tanta atenção, mas mantém os pés assentes na terra: o seu objetivo é que Twelve Minutes venda o suficiente para poder fazer outro jogo, independentemente da sua escala. “Os primeiros anos do Twelve Minutes foi basicamente ter dois trabalhos, trabalhar no The Witness de manhã e no meu jogo à noite. E não quero ter mais dois trabalhos durante muitos mais anos”.

Diz que durante muito tempo era apenas o único a trabalhar no jogo, mas conforme foi crescendo, as expetativas também e já recebeu comparações com o Inside da Playdead, que designer diz que teve um orçamento gigante para cinco ou seis anos de produção com uma equipa de 10 pessoas. “Isto é um jogo muito pequenino e estou um pouco preocupado que as pessoas estejam à espera de algo AAA porque temos os atores e mais exposição. Quero que as pessoas que jogarem o jogo sintam que tenha valido a pena o tempo que gastaram nele. Independentemente das expetativas, pegares no jogo e sentires que foi fixe, que gostes dele”.

O possível regresso a Portugal
Questionado sobre o que sabe da indústria dos videojogos em Portugal e se tem mantido contacto com developers portugueses, a sua resposta é afirmativa. “Sai de Portugal porque não existia na altura uma indústria de videojogos, há cerca de 20 anos”. Confessa que algo que gostava de fazer depois de Twelve Minutes, caso este tenha algum sucesso, era abrir um estúdio m Portugal. No entanto, gosta da sua liberdade de decisão e caso abrisse o estúdio, metade seriam pessoas com quem já trabalhou, sejam americanos ou canadianos. “Iria querer utilizar os contactos internacionais que tenho e que permitiram que este jogo chegasse onde chegou”.

O designer considera que Portugal tem uma indústria de deveopers muito forte e pessoas talentosas. “Só acho é que não exista financiamento para jogos portugueses. Se quiseres fazer um jogo para telemóveis que seja viciante, existe financiamento, mas se quiseres fazer um jogo de time loop como o Twelve Minutes, não há. E no estrangeiro existe muito mais abertura para estes projetos.

Referindo-se à sua ligação com Portugal, Luís António foi o único da família que emigrou e por isso regressa muitas vezes ao país para a visitar. “Os meus filhos nasceram na Califórnia, nos Estados Unidos, mas têm cidadania portuguesa. A minha esposa é canadiana do Quebec e fala francês. Não sinto nenhuma raiz nos Estados Unidos, pois o sistema de saúde e de educação deixa um pouco a desejar, não é algo que desejo para o crescimento das minhas crianças”.

Por isso, embora não tenha planos, gostava de fazer algo em Portugal, “sou português e gostava de dar algo à comunidade de volta”. São planos que estão no ar, dependendo do sucesso de Twelve Minutes e outras propostas que possam surgir no futuro.

Twelve Minutes chega esta quinta-feira dia 19 de agosto ao PC e consolas Xbox, com lançamento gratuito para subscritores do serviço Game Pass.”

+infos(fonte): LINK

+infos(o jogo, na Steam): https://store.steampowered.com/app/1097200/Twelve_Minutes/

Tags : , ,

Mighty 2D Game Dev Assets Bundle (uma campanha)

Com uma contribuição desde 1 euro até 15 euros.. vão de 5 a 31 produtos, que são assets completos para um estilo de videojogo, ou para vários, nos formatos PNG até alguns que incluem o ficheiro editável SVG.

+infos(a campanha): LINK

Tags : , , , , ,

Exportar cultura… um negócio com grandes números

Ficou disponivel um relatório acerca do mercado/desenvolvimento por parte dos estúdios na Finlândia, e os números são impressionantes. Mesmo em 2020 com tudo o que se passou no mundo eles chegam aos patamares dos biliões.. e com recurso a cerca de 30% de mão de obra de fora do país.

+infos(oficial): https://www.playfinland.fi/

Tags :

Oferta de trabalho

Encontrei esta proposta de trabalho..

“// PROCURAMOS PROGRAMADOR COM SKILLS DE GAME DESIGN //
Somos um grupo de jovens criadores teatrais e vamos criar um pequeno videojogo para PC a partir de um conceito que, futuramente, irá ser trabalhado numa peça teatral. Para tal, procuramos agora um programador com skills de game design para criar e implementar este jogo. Queremos encontrar alguém que, para além de executar, colabore no processo de concretizar o conceito num formato e na linguagem de videojogo.
Disponibilidade imediata;Extensão do período de trabalho a definir (cerca de 1 a 2 meses);Trabalho remunerado.
Aos interessados pedimos que enviem CV e/ou portefólio, e/ou links de trabalhos anteriores (podem ser projectos académicos), para: ritadelgado7@hotmail.com.
Estamos disponíveis para responder a qualquer questão não mencionada no anúncio.”

Tags :

A ler..

Estão no mercado dois livros acerca dos jogos de ZX Spectrum:
A Guide to ZX Spectrum Games – 1982 to 1984 por Shaun McClure
A Guide to ZX Spectrum Games – 1985 to 1986 por Shaun McClure

devem ser uma delícia de ser lidos :)

+infos(loja): LINK

Tags : ,

Prémios Playstation talents – 7ª edição

Estão abertas as candidaturas aos prémios Playstation Talents em Portugal. Podem candidatar-se:
pequenos estúdios,
estudantes universitários,
jovens programadores
e empresas portuguesas que tenham facturado menos de 100.000€ em 2020.

Todos os candidatos deverão apresentar uma equipa de projecto composta por, pelo menos, três tipos de perfis: game designer, programador e artista.

Os prémios são atribuídos para:
Categoria Principal
Prémio PlayStation®Talents para Melhor jogo;

Categorias Secundárias
Prémio PlayStation®Talents para Jogo mais Inovador;
Prémio PlayStation®Talents para Melhor Arte;
Prémio PlayStation®Talents para Melhor Utilização das Plataformas PlayStation®;
Prémio PlayStation®Talents para Melhor Jogo Infantil;
Prémio PlayStation®Talents da Imprensa;
Prémio PlayStation®Talents para Melhor Jogo de Competição Online;
Prémio PlayStation®Talents para Melhor Narrativa;

e na Categorias Especiais
Prémio PlayStation®Talents Especial Games for Good

As candidaturas terão de ser enviadas para o endereço de e-mail premiosplaystation@premiosplaystation.com até às 23h59 do próximo dia 30 de Setembro e deverão incluir:
Uma build jogável/vertical slice;
Um vídeo de apresentação do jogo, com um máximo de 5 minutos de duração;
O documento de Concept Design (em formato PDF, sem limite de páginas);
Os CVs dos membros da equipa.

O prémio para o Melhor jogo recebe:
10.000€ em dinheiro para o desenvolvimento do videojogo;
A publicação do jogo na PlayStation Network;
Acesso a ferramentas de desenvolvimento PlayStation;
Uma campanha de promoção e marketing em canais PlayStation avaliada em 50.000€;
Espaço físico em Lisboa para trabalhar no projecto durante 10 meses.

+infos(oficial): http://premiosplaystation.com/

Tags : , , , ,

Um livro para recordar

Não sei se algum destes tempos próximos vou ter tempo, mas gostava de um dia voltar atrás e experimentar novamente o assembly e programar para esta maquina deliciosa que foi o Spectrum! Este é um livro que ajuda a começar, com o título de Spectrum Machine Language for the Absolute Beginner, editado por William Tang.
Esta é uma nova edição de 2020, sendo que encontra por aí versão de PDF de 1982 :)

+infos(loja): LINK

 

Tags :

Free assets no Creative Trio

Encontrei esta referencia, Creative Trio, um website, com alguns assets desenvolvidos para serem usados em videojogos e outros sistemas. Fica aqui o registo desta referência.

+infos(blog): https://creativetrio.art/

Tags : ,

Workshops online, grátis!

A Pan-European Game Information (PEGI) vai dinamizar em setembro dois workshops com uma duração aproximada de uma hora:
16 September @ 2pm -PEGI 101
23 September @ 2pm – The PEGI Labelling and Advertising Guidelines

com o objetivo de:
“a general session on the how, what, when, who, and especially the why of PEGI, followed by a session for PR & Marketing people, with a particular focus on the PEGI Labelling and Advertising Guidelines. Each session will last an hour, with time for Q&A”

Para quem não sabe a PEGI ajuda a catalogar os videojogos na Europa, nomeadamente ajudando a identificar quais as idades apropriadas para serem jogados!

+infos(formulário de inscrição): LINK

+infos(PEGI, oficial): https://pegi.info/

Tags : ,

Procuram-se developers de jogos que não o foram!

A malta do Bitmap books anda à procura de videojogos que foram desenvolvidos e que não foram disponibilizados no mercado. Preferencialmente querem entrevistar game developers para que estes lhes possam contar a(s) história(s) sobre o que se passou :) para isso basta enviar-lhes um email para hello@bitmapbooks.co.uk

Aproveito este post, para identificar que um dos próximos livros (fevereiro/2022) que vai ser disponibilizado no mercado tem como titulo: “Go Straight: The Ultimate Guide to Side-Scrolling Beat ’Em Ups”

 

Proposta de trabalho (em Lisboa)

A malta do OnTop anda à procura de programadores!

+infos(página oficial): https://www.ontopstudios.com/

Tags :

Campanha a decorrer…

Está a decorrer no kickstarter um campanha interessante parar apoiar a “construção” de um documentário em formato de vídeo, sobre a história da industria dos videojogos em Espanha :)
É sempre interessante apoiar e ter acesso a este tipo de informação.

Apesar de estar em espanhol, a apresentação e os vídeos, existe o compromisso de que vai haver uma legenda em inglês :)

+infos(a campanha): LINK

Tags : ,

games press

Um site interessante para verificar o que as editoras andam a dizer dos seus jogos ou perceber o que está a ser publicado :)

+infos(oficial): LINK

Tags : ,