encompass-cs-docs/content/pong/polish/title.md

169 lines
3.8 KiB
Markdown

---
title: "Title"
date: 2019-06-09T16:51:13-07:00
weight: 20
---
It would be nice to have a title screen. Let's make that happen.
I would like us to have a concept of game state. The title menu is a pretty distinct thing from the game itself so it feels nicer to have it be self contained instead of managing extra state in the game world.
Let's create a new class in **game/state.ts**:
```ts
export abstract class State {
public abstract load(): void;
public abstract update(dt: number): void;
public abstract draw(): void;
}
```
Remember, _abstract_ means that the class cannot be used directly, but describes features that exist in inherited classes. So we know that anything we make that inherits from State must have a load(), update(dt), and draw() method.
Let's create a new folder, **game/states**, and put **game.ts** in there. Let's also make it inherit from State:
```ts
export class Game extends State {
```
Let's make a new State called Title. It doesn't need to do much - just display the game title and a prompt for the player to start the game.
```ts
import { State } from "game/state";
export class Title extends State {
private title_font: Font;
private title_text: Text;
private play_font: Font;
private play_text: Text;
public load() {
this.title_font = love.graphics.newFont("game/assets/fonts/Squared Display.ttf", 128);
this.title_text = love.graphics.newText(this.title_font, "Encompass Pong");
this.play_font = love.graphics.newFont("game/assets/fonts/Squared Display.ttf", 32);
this.play_text = love.graphics.newText(this.play_font, "Press Space");
}
public update() {}
public draw() {
love.graphics.draw(
this.title_text,
640,
240,
0,
1,
1,
this.title_text.getWidth() * 0.5,
this.title_text.getHeight() * 0.5,
);
love.graphics.draw(
this.play_text,
640,
480,
0,
1,
1,
this.play_text.getWidth() * 0.5,
this.play_text.getHeight() * 0.5,
);
}
}
```
Now in **main.ts** we can put code to handle our states.
```ts
let menu: Title;
let game: Game;
let current_state: State;
love.load = () => {
...
menu = new Menu();
menu.load();
game = new Game();
game.load();
current_state = menu;
};
love.update = (dt) => {
current_state.update(dt);
if (current_state === menu) {
if (love.keyboard.isDown("space")) {
current_state = game;
}
}
};
love.draw = () => {
current_state.draw();
...
}
```
The final result of **main.ts** should look like this.
```ts
declare global {let PROF_CAPTURE: boolean; }
PROF_CAPTURE = false; // set this to true to enable profiling
import * as jprof from "encompass-jprof";
import { State } from "game/state";
import { Game } from "game/states/game";
import { Title } from "game/states/title";
let menu: Title;
let game: Game;
let current_state: State;
love.load = () => {
love.window.setMode(1280, 720, {vsync: false, msaa: 2});
love.math.setRandomSeed(os.time());
love.mouse.setVisible(false);
menu = new Title();
menu.load();
game = new Game();
game.load();
current_state = menu;
};
love.update = (dt) => {
current_state.update(dt);
if (current_state === menu) {
if (love.keyboard.isDown("space")) {
current_state = game;
}
}
};
love.draw = () => {
current_state.draw();
love.graphics.setBlendMode("alpha");
love.graphics.setColor(1, 1, 1, 1);
love.graphics.print("Current FPS: " + tostring(love.timer.getFPS()), 10, 10);
};
love.quit = () => {
jprof.write("prof.mpack");
return false;
};
```
Let's try it!
![pong title](/images/pong-title.png)
Nice!