Ola pessoal, neste projeto-aprendizado você verão como criar um framework básico no Monkey. Primeiro vamos dar uma olhada no projeto como um todo. Veja:
- Código:
-
Import mojo
'-----------------------------------
' Rocks
'-----------------------------------
' Por Vinicius (Vinians)
' http://monkeybrasil.forumeiros.com
' Projeto Exemplo
'-----------------------------------
'Constantes
Const FPS = 60 'Frames por segundo (desejavel)
Const MAX = 2
'Variaveis Globais
Global score = 0
Global hi = 0
'Inicia tudo aqui
Function Main ()
New Rocks()
End
Class Rocks Extends App
Field actors:Actor[] 'Um array de objetos da classe Actor
Method OnCreate()
SetUpdateRate(FPS)
actors = actors.Resize(MAX) 'Tamanho inicial do Array
For Local i = 0 To actors.Length() - 1
actors[i] = add()
End
End
Method OnUpdate()
If (KeyHit(KEY_A) = 1)
actors = actors.Resize(actors.Length() + 1)
actors[actors.Length() - 1] = add()
End
For Local i = 0 To actors.Length() - 1
actors[i].Update()
End
End
Method OnRender()
Cls(0,0,0)
For Local i = 0 To actors.Length() - 1
actors[i].Draw()
End
DrawText("Clique no objeto para para-lo ou Pressiona A para Adicionar(+)", DeviceWidth() / 2, DeviceHeight() - 8, 0.5, 0.5)
End
Method add:Actor()
Return New Actor(30 + Rnd(DeviceWidth() - 30), 30 + Rnd(DeviceHeight() - 30))
End
End
'Classe Basica
Class Actor Extends Object
Global idCount = 1
Field id:Int 'Apenas um numero de ID
Field x:Float 'Posica X
Field y:Float 'Posicao Y
Field dx:Float 'Deslocamento de X por passo
Field dy:Float 'Deslocamento de Y por passo
Field active:Int 'Ativo sim/nao
Field ray:Float 'Raio
Method New (x:Float, y:Float)
Self.x = x
Self.y = y
dx = Rnd(2, 4)
dy = Rnd(2, 4)
ray = Rnd(10, 25)
active = True
id = idCount
idCount += 1
End
Method Update()
If (active)
x += dx
y += dy
If (x > DeviceWidth - ray) Or (x < ray) dx = -dx
If (y > DeviceHeight - ray) Or (y < ray) dy = -dy
End
If (MouseHit(MOUSE_LEFT))
If Distancia(x, y, MouseX(), MouseY()) < ray
active = Not active
End
End
End
Method Draw()
SetColor(255 - id * 20, id * 20, id * 20)
DrawCircle(x, y, ray)
DrawText(id, x, y, 0.5, 0.5)
End
End
Function Distancia:Float(x1, y1, x2, y2)
Return Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
End
Este exemplo não é um jogo, mas contém vários elementos que utilizamos quando criamos um jogo na plataforma Monkey. Note que esse código é uma preferência minha de criá-lo assim, ou seja existe várias maneiras de se criar um jogo nesta plataforma e esse exemplo ilustra uma delas.
Para ter uma visão geral de como o Monkey funciona de uma olhada no artigo
https://monkeybrasil.forumeiros.com/t10-conhecendo-a-linguagem-monkey-parte-1/,. Como você viu neste artigo, para criar um jogo/aplicação Monkey/mojo você deve criar uma classe
derivada App. Neste exemplo essa nossa
classe se chama Rocks. Veja abaixo o inicio desta classe onde declaramos o campo
actors:
- Código:
-
Class Rocks Extends App
Field actors:Actor[] 'Um array de objetos da classe Actor
.
.
.
Note que temos um campo chamado "
actors" e esse campo é um
vetor com tamanho a ser definido em
tempo de execução. Esse vetor
actors é do tipo
Actor (observe que em Monkey
actor é diferente de
Actor) ou seja, Actor é uma classe que definida por nós enquanto que
actor é um vetor de classes
Actor. Veja que dá pra fazer direto sem usar um objeto Actor, criando diversos campos na classe Rocks, mas isso não é aconselhável pois deixa o código confuso e não permite que ele seja reutilizado facilmente. Ok., vamos ver agora o método
OnCreate que é chamado
automaticamente pelo mojo (Lembre-se que você
derivou sua classe Rocks de App):
- Código:
-
Method OnCreate()
SetUpdateRate(FPS)
actors = actors.Resize(MAX) 'Tamanho inicial do Array
For Local i = 0 To actors.Length() - 1
actors[i] = add()
End
End
.
Neste método, a primeira coisa que fazemos é determinar o FPS (frame por segundo) do nosso game. Depois redimensionamos o nosso array actors para 3 (MAX = 3). Mas ainda precisamos criar cada objeto dentro do array, para isso usamos um loop for e chamamos o método add(). Veja:
- Código:
-
Method add:Actor()
Return New Actor(30 + Rnd(DeviceWidth() - 30), 30 + Rnd(DeviceHeight() - 30))
End
Esse método é só pra facilitar a criação pois podiamos usar o New diretamente no loop,mas como eu vou precisar criar objetos em outras partes do código resolvi criar esse método auxiliar.
Quando utilizamos o operador
New para criar um novo objeto, ele
automaticamente chama o método
New() do objeto que está sendo criado, e você pode colocar os seus próprios parâmetros de acordo com sua necessidade, nesse caso é a coluna e linha onde a nossa bolinha vai iniciar ou seja 2 parâmetros. Vejamos agora o método OnUpdate():
- Código:
-
Method OnUpdate()
If (KeyHit(KEY_A) = 1)
actors = actors.Resize(actors.Length() + 1)
actors[actors.Length() - 1] = add()
End
For Local i = 0 To actors.Length() - 1
actors[i].Update()
End
End
Esse método, assim como o OnCreate() é chamado automaticamente pelo mojo, porem ele é chamado várias vezes por segundo, na verdade é FPS vezes, nesse caso 60. No método OnUpdate() é que damos vida ao nosso jogo. É nele que pegamos a entrada do usuário, processamos e deixamos tudo pronto para ser exibido na tela pelo OnRender(). No caso do nosso exemplo, quando o usuário pressiona "A" ele cria mais um objeto Actor e coloca no nosso vetor. Observe a utilização do método Resize(). Você pode usar Resize() sempre que precisar redimensionar o tamanho do seu array, mas lembre-se de colocar o array a ser dimencionado recebendo o retorno deste método. Assim:
- Código:
-
array = array.Resize(novo_tamanho)
Na verdade ele cria outro array e copia os dados do antigo, mas não se importe com isso agora. Pra todos os efeitos ele redimensiona o array.
Agora, vamos analisar a outra parte, onde temos um loop For que faz iteração em todos os elementos do nosso array actors:
- Código:
-
For Local i = 0 To actors.Length() - 1
actors[i].Update()
End
Aqui tem uma coisa interessante. Observe que chamamos o método
Update() do nosso objeto actor que esta "dentro" do
array actors e ele (o Update) faz todo o trabalho. Isso é MUITO importante pois encapsula o comportamento do objeto. Basta imaginar o seguinte: se tivessemos vários objetos que herdasse do obejto base Actor() poderiamos ter em um MESMO vetor objetos varios tipos de objetos desde que esses objetos
HERDASSEM da mesma classe base. Pretendo mostrar isso em um outro projeto de exemplo.
Agora, vejamos o método OnRender() responsavel por "desenhar" tudo na tela.
- Código:
-
Method OnRender()
Cls(0,0,0)
For Local i = 0 To actors.Length() - 1
actors[i].Draw()
End
DrawText("Clique no objeto para para-lo ou Pressiona A para Adicionar(+)", DeviceWidth() / 2, DeviceHeight() - 8, 0.5, 0.5)
End
Neste método basicamente limpamos a tela com o
Cls(0,0,0) (preto) depois mais uma vez chamamos um método que faz todo trabalho pesado pra nós, o método
Draw() de cada objeto. Por fim escrevemos na tela uma mensagem.
Agora, vamos ver o objeto Actor() que é responsavel pelo trabalho "pesado" neste exemplo.
- Código:
-
Class Actor Extends Object
Global idCount = 1
Field id:Int 'Apenas um numero de ID
Field x:Float 'Posica X
Field y:Float 'Posicao Y
Field dx:Float 'Deslocamento de X por passo
Field dy:Float 'Deslocamento de Y por passo
Field active:Int 'Ativo sim/nao
Field ray:Float 'Raio
Method New (x:Float, y:Float)
Self.x = x
Self.y = y
dx = Rnd(2, 4)
dy = Rnd(2, 4)
ray = Rnd(10, 25)
active = True
id = idCount
idCount += 1
End
Method Update()
If (active)
x += dx
y += dy
If (x > DeviceWidth - ray) Or (x < ray) dx = -dx
If (y > DeviceHeight - ray) Or (y < ray) dy = -dy
End
If (MouseHit(MOUSE_LEFT))
If Distancia(x, y, MouseX(), MouseY()) < ray
active = Not active
End
End
End
Method Draw()
SetColor(255 - id * 20, id * 20, id * 20)
DrawCircle(x, y, ray)
DrawText(id, x, y, 0.5, 0.5)
End
End
A classe
Actor() contem campos para controlar uma instância de nossa bolinha na tela. Contem sua posição, seu raio, o valor de seu deslocamento a cada passo em que
Update() for chamado. Além diso tem um campo "
active" que pode ser usado para "parar" aquela instância, nós usamos essa variável quando clicamos na bolinha. Também temos nessa classe 2 métodos:
Update() e
Draw(). O método
Update() é o
motor da instância enquanto que
Draw() seria sua
aparência. É muito importante separamos comportamento de aparência se quizemos nos dar bem no Monkey. (e em quase todos os frameworks atuais).
Nosso método
Update() faz 2 trabalhos, primeiro ele move a instancia para sua nova posicão usando dx e dy (lembra do hspeed e vspeed do GM?) depois ele verifica se clicamos com o botão esquerdo do mouse
MouseHit(MOUSE_LEFT).
Para saber se o nosso clique foi na instancia que estamos testando basta calcular a
distância entre o ponteiro do mouse
MouseX() e
MouseY() e a nossa posição
x e y. Em caso positivo,
invertemos o valor da variável
avtive. Obs: quando fazemos
variavel_booleana = Not variavel_booleana ela inverte o seu valor ou seja, se era TRUE fica FALSE e vice-versa.
Agora por fim, temos o nosso método
Draw() que apenas "desenha" a instância na posição atual da mesma. Note que isso poderia ser uma imagem, um quadrado, ou qualquer outra coisa que quizessemos.
Pra finalizar temos apenas uma função gerenérica de cálculo de distância que pode ser usada em outros projetos nossos, por isso eu coloquei como função, pois se colocasse como método de Actor() eu não poderia usar em outros objetos.
Então é isso pessoal, espero que esse projeto possa clarear o caminho de vocês na criação de seus jogos. Embora falta muita coisa, você pode usar como base. Em breve postarei um jogo simples que usará esse projeto como base. Até !