protected override void OnUpdateFrame(FrameEventArgs e) { if (State == GameState.Active) { base.OnUpdateFrame(e); ProcessEvents(); // remover todas as bolas que saíram da tela Balls.RemoveAll(b => b.Position.Y >= Height); // condição de derrota if (Balls.Count == 0) { Lives--; if (Lives == 0) { State = GameState.Lost; PostProcessor.Chaos = false; PostProcessor.Confuse = true; return; } Balls.Add(Ball); ResetPlayer(); } // caso contrário, selecionar a bola principal como uma das bolas restantes else { Ball = Balls[0]; if (!Ball.Comet) { Ball.Color = new Vector3(1); } } // mover o jogador de acordo com a posição do mouse float x = Math.Max(Math.Min((float)(Player.Position.X + (PLAYER_VELOCITY * e.Time)), Width - Player.Size.X), 0); if (x <= 0 || x >= Width - Player.Size.X) { Player.Velocity = Vector2.Zero; } else { Player.Velocity = new Vector2((float)(PLAYER_VELOCITY * e.Time), 0); } Player.Position = new Vector2(x, Player.Position.Y); // mover todas as bolas existentes na tela Balls.ForEach(ball => { ball.Move((float)e.Time, Width); if (ball.Stuck) { ball.Position += Player.Velocity; } }); // atualizar a posição das partículas de rastro da bola principal ParticleGenerator.Update((float)e.Time, Ball, 2, new Vector2(Ball.Radius / 2f)); // atualizar o estado de todos os powerups UpdatePowerUps((float)e.Time); // checar colisão DoCollisions(); // atualizar o tempo restante do efeito de "shake" if (shakeTime > 0) { shakeTime -= (float)e.Time; if (shakeTime <= 0) { PostProcessor.Shake = false; } } score = Levels[Level].GetScore(); } }
protected override void OnRenderFrame(FrameEventArgs e) { base.OnRenderFrame(e); // limpar o buffer de cor do openGL GL.Clear(ClearBufferMask.ColorBufferBit); // encapsular a renderização de objetos para permitir efeitos de pós-processamento PostProcessor.BeginRender(); //renderizar o background Renderer.DrawTexture(ResourceManager.GetTex("breakout_bg"), Vector2.Zero, new Vector2(Width, Height), 0, Vector3.One); // desenhar os "tijolos" Levels[Level].Draw(Renderer); //desenhar o jogador Player.Draw(Renderer); //desenhar as partículas de rastro ParticleGenerator.Draw(); //desenhar todas as bolas Balls.ForEach(ball => ball.Draw(Renderer)); //desenhar os powerups PowerUps.ForEach(p => { if (!p.Destroyed) { p.Draw(Renderer); } }); PostProcessor.EndRender(); // aplicar efeitos de pós-processamento PostProcessor.Render((float)e.Time); // renderizar textos informativos na tela, dependendo do estado do jogo. // textos não devem passar pelos efeitos de pós processamento // suporte a acentuação não foi implementado if (State == GameState.Active || State == GameState.Paused) { TextRenderer.RenderText($"Vidas: {Lives}", 5, 5, 1); TextRenderer.RenderText("Efeitos:", 15, Height - 75, .95f); // instrução de pressionar espaço só deve ser exibida até que o jogador pressione espaço if (drawInstruction) { TextRenderer.RenderText("Pressione espaco", (Width / 2) - 120f, (Height / 2) + 80f, 1); } // desenhar os powerups que estão ativos no momento for (int i = 0; i < PowerUps.Count; i++) { if (PowerUps[i].Active) { Renderer.DrawTexture(PowerUps[i].Sprite, new Vector2(30 + (i * PowerUps[i].Size.X), Height - (1.1f * PowerUps[i].Size.Y)), PowerUps[i].Size / 1.25f, 0, Color.DeepPink.ToVector3()); } } } if (State == GameState.Menu) { TextRenderer.RenderText("Pressione ENTER para iniciar", (Width / 2f) - 200, (Height / 2f) + 20f, 1); TextRenderer.RenderText("Pressione W ou S para selecionar a fase", (Width / 2f) - 225f, (Height / 2f) + 50f, .8f); TextRenderer.RenderText("Pressione I para INFO", (Width / 2f) - 95f, (Height / 2f) + 80f, .6f); TextRenderer.RenderText($"Dificuldade: {Difficulty.Name}", (Width / 2) - 110, Height * .7f, .8f); // tela informativa com instruções sobre como jogar if (showInfo) { Renderer.DrawTexture(Overlay, Vector2.Zero, new Vector2(Width, Height), 0, Color.DarkSlateGray.ToVector4(.8f)); TextRenderer.RenderText("INFO", (Width / 2) - 75, 16, 2); TextRenderer.RenderText("Bem vindo ao TIJOLATOR!", 15, 16 * 5, .8f); TextRenderer.RenderText("Para mudar a dificuldade, pressione [1], [2] ou [3]", 15, 16 * 7.5f, .8f); TextRenderer.RenderText("O mouse movimenta a barra de acordo com sua posicao", 15, 16 * 9.5f, .8f); TextRenderer.RenderText("relativa ao centro da tela, sendo que quanto mais", 15, 16 * 11, .8f); TextRenderer.RenderText("perto da borda, mais velocidade naquela direcao a", 15, 16 * 12.5f, .8f); TextRenderer.RenderText("barra tem", 15, 16 * 14, .8f); TextRenderer.RenderText("O botao da esquerda pausa, e o da direita imprime ", 15, 16 * 17, .8f); TextRenderer.RenderText("informacoes tecnicas.", 15, 16 * 18.5f, .8f); TextRenderer.RenderText("Quando a bola grudar na barra,", 15, 16 * 20.5f, .8f); TextRenderer.RenderText("aperte espaco para solta-la", 15, 16 * 22, .8f); TextRenderer.RenderText("Por fim:", 15, 16 * 25, .8f); TextRenderer.RenderText("LET'S TIJOLATE!", (Width / 2) - 170, 16 * 32, 1.5f); } } if (State == GameState.Win) { TextRenderer.RenderText("Venceste!!!", (Width / 2f) - 75f, (Height / 2f) + 280f, 1f, new Vector3(0f, 1f, 0f)); } if (State == GameState.Lost) { TextRenderer.RenderText("Perdeste! :(", (Width / 2f) - 75f, (Height / 2f) - 100f, 1f, new Vector3(1f, 0f, 0f)); TextRenderer.RenderText("Pressione R para voltar ao menu", (Width / 2f) - 225f, (Height / 2f) - 70f, 1f, Vector3.Zero); } if (State != GameState.Menu) { TextRenderer.RenderText($"Score: {score}", Width - 150, 5, 1, State == GameState.Lost ? Vector3.Zero : Vector3.One); } // condição de vitória if (State == GameState.Active && Levels[Level].IsCompleted()) { Levels[Level].Reload(Width, Height / 2); PostProcessor.Confuse = false; PostProcessor.Chaos = true; State = GameState.Win; } // pause decorrente do botão direito do mouse if (shouldPause) { State = GameState.Paused; shouldPause = false; LogInfo(); } if (State == GameState.Paused) { Renderer.DrawTexture(Overlay, Vector2.Zero, new Vector2(Width, Height), 0, Color.DarkSlateGray.ToVector4(.4f)); TextRenderer.RenderText("PAUSE", (Width / 2f) - 75, Height / 2f, 2); for (int line = 0; line < lines.Length; line++) { var height = line * TextRenderer.Characters['T'].Size.Y; bool secondColumn = height > Width - 15; TextRenderer.RenderText(lines[line], 5 + (secondColumn ? Width / 2 : 0), 5 + (secondColumn ? height - Height + 75 : height), .55f, Color.Yellow.ToVector3()); } } Context.SwapBuffers(); }
//Método responsável por inicializar todos os recursos utilizados no jogo public void Init() { // carregar sons var bgm = ResourceManager.LoadSound("resources/bgm.mp3", "bgm", true); SoundEngine.Instance.PlaySound(bgm); ResourceManager.LoadSound("resources/bleep.wav", "bleepPaddle"); ResourceManager.LoadSound("resources/powerup.wav", "powerup"); ResourceManager.LoadSound("resources/solid.wav", "solid"); ResourceManager.LoadSound("resources/bleep.mp3", "bleepBrick"); //carregar shaders ResourceManager.LoadShader("shaders/sprite.vert", "shaders/sprite.frag", "sprite"); ResourceManager.LoadShader("shaders/particle.vert", "shaders/particle.frag", "particle"); ResourceManager.LoadShader("shaders/postProcessing.vert", "shaders/postProcessing.frag", "postProcessing"); //instanciar a matriz de projeção ortogonal var projection = Matrix4.CreateOrthographicOffCenter(0, Width, Height, 0, -1, 1); // instanciar o renderizador padrão de texturas var spriteshader = ResourceManager.GetShader("sprite"); var particleshader = ResourceManager.GetShader("particle"); spriteshader.SetInteger("image", 0, true); spriteshader.SetMatrix4("projection", projection, true); particleshader.SetInteger("sprite", 0, true); particleshader.SetMatrix4("projection", projection, true); Renderer = new Renderer2D(spriteshader); // carregar as texturas do jogo ResourceManager.LoadTexture("resources/ball.png", "ball"); ResourceManager.LoadTexture("resources/paddle.png", "paddle"); ResourceManager.LoadTexture("resources/block.png", "block", false); ResourceManager.LoadTexture("resources/block_solid.png", "block_solid", false); ResourceManager.LoadTexture("resources/background.jpg", "breakout_bg", false); ResourceManager.LoadTexture("resources/particle.png", "particle"); ResourceManager.LoadTexture("resources/speed.png", "speed"); ResourceManager.LoadTexture("resources/meteor.png", "comet"); ResourceManager.LoadTexture("resources/width.png", "padIncrease"); ResourceManager.LoadTexture("resources/shrink.png", "padDecrease"); ResourceManager.LoadTexture("resources/multiply.png", "multiply"); ResourceManager.LoadTexture("resources/sticky.png", "sticky"); ResourceManager.LoadTexture("resources/confuse.png", "confuse"); ResourceManager.LoadTexture("resources/skull.png", "chaos"); //carregar os níveis disponíveis no jogo GameLevel one = new GameLevel(); one.Load("levels/one.lvl", Width, Height / 2); GameLevel two = new GameLevel(); two.Load("levels/two.lvl", Width, Height / 2); GameLevel three = new GameLevel(); three.Load("levels/three.lvl", Width, Height / 2); GameLevel four = new GameLevel(); four.Load("levels/four.lvl", Width, Height / 2); GameLevel five = new GameLevel(); five.Load("levels/five.lvl", Width, Height / 2); GameLevel six = new GameLevel(); six.Load("levels/six.lvl", Width, Height / 2); Levels.Add(one); Levels.Add(two); Levels.Add(three); Levels.Add(four); Levels.Add(five); Levels.Add(six); Level = 4; // instanciar jogador const float offset = 84f; Vector2 playerStartPos = new Vector2((Width / 2) - (PLAYER_SIZE.X / 2), Height - PLAYER_SIZE.Y - offset); Player = new GameObject(playerStartPos, PLAYER_SIZE, ResourceManager.GetTex("paddle")); // instanciar bola Vector2 ballStartPos = playerStartPos + new Vector2((Player.Size.X / 2f) - BALL_RADIUS, -BALL_RADIUS * 2f); Ball = new BallObject(ballStartPos, BALL_RADIUS, ResourceManager.GetTex("ball"), Color.Pink.ToVector3(), velocity: new Vector2(GetRandomBallSpeed(), Difficulty.BallUpSpeed)); Balls.Add(Ball); // instanciar gerador de partículas para efeito de "rastro" ParticleGenerator = new ParticleGenerator(ResourceManager.GetShader("particle"), ResourceManager.GetTex("particle"), 500); // instanciar classe responsável pelos efeitos de pós-processamento PostProcessor = new PostProcessor(ResourceManager.GetShader("postProcessing"), Width, Height); // iniciar renderizador de texto TextRenderer = new TextRenderer(Width, Height); TextRenderer.Load("fonts/ocraext.TTF", 24); // iniciar overlay para tela de "pause" Overlay = new Texture2D(); Overlay.Generate(Width, Height, IntPtr.Zero); // setar a posição inicial do mouse para o meio da tela var point = PointToScreen(new Point(Width / 2, Height / 2)); Mouse.SetPosition(point.X, point.Y); // estado inicial do jogo deve ser o menu State = GameState.Menu; }