Buscar

Banco de dados para MMORPG

Prévia do material em texto

Banco de Dados para MMORPG
Paulo Renato Kinjo
 
1Curso de Ciência da Computação - Pontifícia Universidade Católica do Rio Grande do Sul (PUCRS) Av. Ipiranga, 6681 - Partenon - Porto Alegre/RS - CEP: 90619-900
paulo.kinjo@acad.pucrs.br
 
Resumo. Este artigo apresenta um projeto que utiliza um sistema de banco de dados. Ao que se segue será apresentado o projeto de um sistema que armazena dados para um jogo MMORPG, que de forma genérica pode ser usando tanto em uma rede local quanto na internet, ou seja, pode evoluir e ser utilizado por diversos usuários online. O texto que se segue não pretende mostrar todo o poder que banco de dados ORACLE pode fornecer aos desenvolvedores, mais pretendemos mostrar como é prático e divertido trabalhar com este sistema.
 
Palavras-chaves: MMORPG; Rede Local; Internet; Oracle. 
 
Database MMORPG
Abstract. This article presents a project that uses a database. In what follows will be presented the design of a system that stores data for a MMORPG game that can generically be using both on a local network and the Internet, that is, he level up and can be used by several users. The text that follows is not intended to show all the power ORACLE’S database can provide developers, most intend to show how is practical and fun to work with this system.
 Keywords: MMORPG; Local Network; Internet; Oracle
 
1 Introdução
O projeto visa desenvolver um banco de dados para um jogo de MMORPG (Massively Multiplayer Online Role-playing Game). O jogo permite armazenar jogadores, personagens, classes de personagens, poderes de classes, armas, proteção e itens para consumo. Os jogadores podem batalhar uns com os outros. Cada jogador pode possuir até 5 (cinco) personagens sendo que é possível escolher apenas um para iniciar o jogo. Cada personagem contém uma classe, uma arma, cinco proteções (cabeça, peito, pernas, mãos e pés) e um item de consumo. Inicialmente há cinco classes para jogadores e cinco classes para os inimigos no jogo, porém futuramente podem ser cadastradas novas classes assim como os poderes, ou seja, o jogo pode ser expandido. 
Cada classe possui um leque de poderes específicos e comuns a outras classes. O ataque é feito somente com uma arma e os poderes servem apenas para aumentar/diminuir os atributos do personagem assim como os itens de consumo. Dependendo do item de consumo os efeitos duram por um determinado tempo.
2 Definindo as Tabelas
Tabelas em bancos de dados representam entidades (e.g., pessoas, veículos, planetas, etc). Por convenção utilizaremos caixa baixa para denominar nomes de tabelas e nomes de atributos, e caixa alta para denominar comandos SQL, embora o SQL não faça distinção entre caixa alta ou baixa. Para representar as entidades do nosso projeto, vamos tomar como base informações do sistema que são permanentes, ou seja, que possuem dados que devem ficar armazenados no banco de dados. O jogo possui as seguintes tabelas: jogador, poder, tipo_poder, classe, poder_classe, tipo_protecao, proteção, tipo_arma, arma, personagem, tipo_item_consumo, proteção_personagem, consumo, consumo_personagem
2.1 Jogador
A entidade jogador possui os seguintes atributos: nome, cpf, email, login e senha. E o seguinte script[2] cria a tabela jogador: 
	CREATE TABLE jogador(
	
	
	cod_jogador
	NUMBER(4),
	
	nome
	VARCHAR2(60)
	NOT NULL,
	cpf
	VARCHAR2(14)
	NOT NULL,
	email
	VARCHAR2(100)
	NOT NULL,
	login
	VARCHAR2(20)
	NOT NULL,
	senha
	VARCHAR2(13)
	NOT NULL
	)
	
	
Cada atributo representa uma coluna da tabela (cod_jogador representa a chave primaria da tabela[1]). Repare nos comando SQL (definidos por convenção em caixa alta) a frente de cada atributo, ao criarmos uma tabela devemos especificar para o SGBD (Sistema Gerenciador de Banco de Dados), que tipo de dado será armazenado naquele campo (e.g., número, texto, letra, data e etc).
Atenção: Devemos criar nossas tabelas seguindo um raciocínio lógico, onde, uma tabela só deve ser criada em uma ordem lógica e estruturada, como por exemplo: criamos a tabela jogador antes da tabela personagem, por que não faria sentido criar um personagem sem antes existir um jogador (embora seja permitido cria uma tabela personagem ante de uma tabela jogar, para efeitos de clareza vamos seguir a lógica). Campos definidos como NOT NULL informam ao SGBD que estes campos são de preenchimento obrigatório.
 
2.2 Poder
A entidade poder possui os seguintes atributos: nome, taxa (representa a porcentagem do dano),
bonus , duração e consumo. O seguinte script [2] cria a tabela poder:
	CREATE TABLE poder(
	
	
	cod_poder
	NUMBER(4), 
	
	tipo_poder
	NUMBER(4),
	
	nome
	VARCHAR2(60)
	NOT NULL,
	taxa
	NUMBER(5,2)
	DEFAULT 0,
	bonus
	NUMBER(4)
	DEFAULT 0,
	duracao
	NUMBER(4)
	DEFAULT 0,
	consumo
	NUMBER(4)
	DEFAULT 0
	)
	
	
Campos numéricos podem ser declarados com um valor padrão (DEFAULT) mantendo assim a integridade dos dados. Observe o campo tipo_poder da tabela acima, este campo pode assumir os valores: Ataque, Defesa, Cura e Penalidade. Observe que toda vez que inserirmos um poder em nossa tabela temos que inserir qual o tipo desse poder, porém poderes podem referenciar um mesmo tipo (e.g, Fúria dos Deuses e Ataque Mortal representam o tipo de poder denominado Ataque) então teremos que referenciar um tipo de poder diversas vezes ao inserirmos dados na tabela acima. Agora observe o script a seguir: 
	CREATE TABLE tipo_poder ( 	
	
	
	cod_tipo_poder
	NUMBER(4),
	
	nome
	VARCHAR2(20)
	NOT NULL
	)
	
	
Foram criadas duas tabelas tipo_poder e poder, agora podemos cadastra na tabela tipo_poder os valores: Ataque, Defesa, Cura e Penalidade. Na tabela poder o campo cod_tipo_poder representa o código do poder que estamos fazendo referência, assim quando quisermos acrescentar ou alterar algum tipo de poder faremos apenas na tabela tipo_poder e a alteração então será realizada automaticamente na tabela poder que faz referência a tabela tipo_poder.
2.3 Classe
A entidade classe possui os seguintes atributos: nome, taxa e
bonus. O seguinte script [2] cria a tabela classe: 
	CREATE TABLE classe(
	
	
	cod_classe
	NUMBER(4),
	
	nome
	VARCHAR2(60)
	NOT NULL,
	taxa
	NUMBER(5,2)
	DEFAULT 0,
	bonus
	NUMBER(4)
	
	)
	
	
A criação da tabela classe é bem simples, mas agora temos que pensar que uma classe possui poderes, e esses poderes são diferentes para diferentes classes (e.g., um mago possui o poder de cura, mas não possui o poder de regeneração, e um lobo possui o poder de regeneração, mas não possui o poder de cura). Com este pensamento temos uma relação de muitos para muitos[3], onde um poder pode referenciar uma ou mais classes e uma classe pode referenciar um ou mais poderes. Devemos então criar uma tabela que ira representar este relacionamento: 
	CREATE TABLE poder_classe (
	
	cod_poder_classe
	NUMBER(4),
	cod_poder
	NUMBER(4),
	cod_classe
	NUMBER(4)
	)
	
Está tabela faz referência a tabela poder e a tabela classe, e é aqui que devemos inserir os relacionamentos entre elas de acordo com as regras do jogo.
2.4 Proteção
De forma análoga a entidade poder, nossa entidade protecao possui um tipo (e.g., Cabeça, Peito, Mãos, Pés e Calça), então teremos que cria uma tabela chamada tipo_protecao, que servirá como referência para a nossa tabela protecao. O seguinte script define as tabelas tipo_protecao e protecao:
	CREATE TABLE tipo_protecao(
	
	
	cod_tipo_protecao
	NUMBER(4),
	
	nome
	VARCHAR2(30)
	NOT NULL,
	)
	
	
	
CREATE TABLE protecao (
	
	
	cod_protecao
	NUMBER(4),
	
	cod_tipo_protecao
	NUMBER(4),
	
	nome
	VARCHAR2(60)
	NOT NULL,
	defesa
	NUMBER(5)
	DEFAULT 0,
	bonus 	 
	NUMBER(5)
	DEFAULT 0,
	absorcao
	NUMBER(5,2)
	DEFAULT 0,
	amplificacao
	NUMBER(5,2)
	DEFAULT 0,
	durabilidade
	NUMBER(5)
	DEFAULT 0
	)
	
	
2.5 Arma
A entidade arma possui um atributo tipo (e.g., Arco, Arma Branca,Arma de Fogo, Bastão e Adaga), que de acordo com os exemplos visto até agora deve ser representado como uma entidade. O script a seguir cria as tabelas tipo_arma e arma: 
	CREATE TABLE tipo_arma(
	
	
	cod_tipo_arma
	NUMBER(4),
	
	nome
	VARCHAR2(60)
	NOT NULL
	)
	
	
	CREATE TABLE arma(
	
	
	cod_arma
	NUMBER(4),
	
	cod_tipo_arma
	NUMBER(4),
	
	nome
	VARCHAR2(60)
	NOT NULL,
	ataque
	NUMBER(5)
	DEFAULT 0,
	bonus
	NUMBER(5)
	DEFAULT 0,
	amplificacao
	NUMBER(5,2)
	DEFAULT 0,
	distancia
	NUMBER(5)
	DEFAULT 0,
	durabilidade
	NUMBER(5)
	DEFAULT 0
	)
	
	
2.6 Personagem
Para definirmos uma entidade personagem, o nosso jogo exige que o personagem seja criado por um jogador, possua uma classe e inicie com uma arma correspondente a sua classe. A seguir o script que cria a entidade personagem:
 
	CREATE TABLE personagem ( 
	
	
	cod_personagem
	NUMBER(4),
	
	cod_jogador
	NUMBER(4),
	
	cod_classe
	NUMBER(4),
	
	cod_arma
	NUMBER(4),
	
	nome
	VARCHAR2(60)
	NOT NULL,
	sexo
	CHAR(1)
	NOT NULL,
	vitalidade
	NUMBER(4)
	DEFAULT 1000,
	magia
	NUMBER(4)
	DEFAULT 100,
	ataque
	NUMBER(4)
	DEFAULT 100,
	defesa
	NUMBER(4)
	DEFAULT 100
	)
	
	
2.7 Consumo
Jogadores podem consumir itens para que seus personagens fiquem mais fortes temporariamente, recuperem vida instantaneamente, recupere magia e etc. Todos os itens de consumo possuem tipo (e.g., sanduiche que recupera vida).
	CREATE TABLE tipo_item_consumo(	
	
	
	 cod_tipo_item_consumo
	NUMBER(4),
	
	Nome
	VARCHAR2(60)
	NOT NULL
	)
	
	
	CREATE TABLE consumo (
	
	
	cod_consumo
	NUMBER(4),
	
	cod_tipo_item_consumo
	NUMBER(4), 
	
	nome
	VARCHAR2(60)
	NOT NULL,
	absorcao
	NUMBER(5,2)
	DEFAULT 0,
	amplificacao
	NUMBER(5,2)
	DEFAULT 0,
	bonus
	NUMBER(5)
	DEFAULT 0,
	duracao
	NUMBER(5)
	DEFAULT 0,
	descricao
	VARCHAR2(200)
	NOT NULL
	)
	
	
3 Definindo Relacionamentos entre tabelas
Até o momento nós apenas definimos as tabelas e os atributos que queremos representar relacionamentos com outras tabelas, mas o SGBD precisa ser informado sobre essa intenção, e é isso que iremos fazer a seguir.
 
3.1 Poder Classe
No item 2.3 definimos a tabela classe e a tabela poder_classe que faz referência a tabela poder do item 2.2. Agora devemos informar ao SGBD qual é o tipo de relacionamento que queremos que está tabela represente, mas para isso devemos definir chaves primarias[2], para as tabelas envolvidas. A seguir definimos as chaves primarias para as tabelas classe, poder e tipo_poder (lembre-se que devemos seguir um raciocínio lógico na hora de criar ou definir nossas tabelas), observe:
	ALTER TABLE tipo_poder ADD(CONSTRAINT PK_TIPO_PODER PRIMARY KEY (cod_tipo_poder))
(Define o atributo cod_tipo_poder como chave primaria da tabela tipo_poder)
 
ALTER TABLE poder ADD(CONSTRAINT PK_PODER PRIMARY KEY(cod_poder))
(Define o atributo cod_poder como chave primaria da tabela poder)
 
ALTER TABLE classe ADD (CONSTRAINT PK_CLASSE PRIMARY KEY (cod_classe))
(Define o atributo cod_classe como chave primaria da tabela classe)
 
ALTER TABLE poder_classe ADD(CONSTRAINT PK_PODER_CLASSE PRIMARY KEY (cod_poder_classe))
(define o atributo cod_poder_classe como chave primaria da tabela poder_classe)
 
Podemos observar a construção do raciocínio estrutural, onde, se queremos fazer referencias entre as tabelas poder e classe, devemos definir chaves primarias que servirão como referencias para a tabela poder_classe, e não menos importante se vamos definir um referência da tabela poder para a tabela tipo_poder obviamente devemos então definir uma chave primaria para a tabela tipo_poder. E agora que definimos as chaves primarias, ou seja, agora podemos finalmente definir a relação entre as tabelas através das chamadas chaves estrangeiras [2].
 
	ALTER TABLE poder ADD(CONSTRAINT FK_TIPO_PODER FOREIGN KEY(cod_tipo_poder) REFERENCES TIPO_PODER(cod_tipo_poder))
(Define o atributo cod_tipo_poder como chave estrangeira da tabela poder, fazendo referencia a chave primaria da tabela poder)
 
ALTER TABLE poder_classe ADD(CONSTRAINT FK_PODER FOREIGN KEY (cod_poder) REFERENCES PODER (cod_poder))
(Define o atributo cod_poder como chave estrangeira da tabela poder_classe, fazendo referencia a chave primaria da tabela poder)
 ALTER TABLE poder_classe ADD(CONSTRAINT FK_CLASSE FOREIGN KEY (cod_classe) REFERENCES CLASSE (cod_classe))
(Define o atributo cod_classe como chave estrangeira da tabela poder_classe, fazendo referencia a chave primaria da tabela classe)
 
Na primeira alteração apenas definimos uma chave estrangeira na tabela poder para fazermos referencia a tabela tipo_poder. Nas outras duas alteração definimos duas chaves estrangeiras, o que nos da uma chave composta.
 
3.2 Protecao Personagem
	CREATE TABLE protecao_personagem(
	
	cod_protecao_personagem
	NUMBER (4),
	cod_personagem
	NUMBER (4),
	cod_protecao
	NUMBER (4) 
	)
	
3.3 Consumo Personagem
O relacionamento a seguir serve para armazenar em nosso sistema todos os itens que os personagens vierem a consumir, e como um personagem pode consumir diversos itens e um item pode ser consumido por diversos personagens, temos um relacionamento muitos para muitos e a tabela consumo_personagem representa este relacionamento.
	CREATE TABLE consumo_personagem (
	
	cod_consumo_personagem
	NUMBER(4),
	cod_consumo
	NUMBER(4), 
	cod_personagem
	NUMBER(4)
	)
	
4 Um exemplo de utilização
A partir de agora vamos executar alguns comando para testar o nosso banco de dados e observar como ele se comporta.
 
a) Um comando SELECT que envolva mais de uma tabela:
O comando seguinte faz um pedido ao SGBD: Selecione o nome do jogaodor, o nome do personagem, o nome da classe, o sexo, a vitalidade, a magia, o ataque e defesa da tabela personagem onde o campo cod_jogador da tabela jogador seja igual ao campo cod_jogador da tabela personagem e tambem aonde o campo cod_classe da tabela classe seja igual ao campo cod_classe da tabela personagem: 
	 SELECT J.nome AS JOGADOR, P.nome AS PERSONAGEM_NOME, C.nome AS CLASSE, P.SEXO, P.VITALIDADE, P.MAGIA, P.ATAQUE, P.DEFESA
FROM
JOGADOR J INNER JOIN PERSONAGEM P
ON J.COD_JOGADOR = P.COD_JOGADOR
INNER JOIN CLASSE C ON C.COD_CLASSE = P.COD_CLASSE
b) Um comando SELECT que envolva uma função de agregação:
Selecione a quantidade de jogadores cadastrados na tabela jogado: 
	 SELECT COUNT(*) AS "Jogadores cadastrados" FROM JOGADOR 
c) Um comando SELECT que envolva uma sub-consulta ou um agrupamento: 
	 SELECT J.NOME AS JOGADOR, C.NOME AS CLASSE, P.NOME
FROM JOGADOR J INNER JOIN PERSONAGEM P ON J.COD_JOGADOR = P.COD_JOGADOR
INNER JOIN CLASSE C ON C.COD_CLASSE = P.COD_CLASSE
WHERE COD_ARMA IN (SELECT COD_TIPO_ARMA FROM TIPO_ARMA WHERE NOME = 'ARCO' OR NOME = 'ADAGA') 
d) Um comando UPDATE
 
e) Um comando DELETE que envolva sub-consulta
5 Conclusão
Na prática representar um jogo rpg pode ser muito complexo, como foi mencionado esta é apenas a primeira parte do projeto, porém o primeiro passo já foi dado, agora temos uma visão geral de como ou para onde o sistema deve caminhar e como podemos evoluí-lo daqui em diante. Em um primeiro momento nós apenas escrevemos códigos sem nem parar para pensar no projeto como um todo, não podemos esquecer que existem bancos de dados que são totalmente livres como o postgrees[1] (mas que não possuem todo o poder de um banco de dados com licença paga – mas pode ser útil dependendo do projeto), dependendo do nosso objetivo um sistema pago pode ser a melhor opção ou a mais barata (uma ferramenta que lhe da todo o suporte para o desenvolvimento pode lhe poupar tempo que no momento é uma das coisas mais preciosas que possuirmos), isso, só pode ser definido previamente após realizar um projeto detalhado do sistema como um todo.
6 Referências
[1] 4634A-02 - Laboratório de Banco de Dados I - Turma168 - 2012/2 - Prof. Daniel Callegari. Notas de aulas
[2] ELSMARI, R.; NAVATHE, S.B. Sistemas de Banco de Dados. 6. Ed. Pearson Brasil.
[3]

Mais conteúdos dessa disciplina