经过了前面10章漫长的旅程,我们终于要达成我们的目标了:在一个完全由自己实现的计算机平台上运行一个小游戏。这个小游戏要经过编写、编译、转换虚拟机字节码、汇编、生成机器代码等步骤,最终运行在自己搭建的虚拟计算机上。在游戏的运行过程中,每一条指令都是我们亲手编写,每一个细节我们都了如指掌,是我们完完全全地创造了它(虽然需要基于一个硬件虚拟机),这确实是一件非常有意思的事情。
骑手快跑
我这里编写了一个非常简单的小游戏:骑手快跑。在屏幕上会位置随机地出现食物和房子,我们扮演骑手,通过上下左右键控制骑手的行动。骑手需要先取到食物装到车上,然后运送到房子处并领取奖励金,完成配送后骑手又可以继续配送下一单,当奖励金达到一定数额后游戏通关🙄。





实现
main() 先创建游戏实例,然后运行游戏,游戏结束后调用 dispose() 回收内存
class Main {
function void main() {
var RunnerGame game;
do RunnerGame.newInstance();
let game = RunnerGame.getInstance();
do game.run();
do game.dispose();
return;
}
}
RunnerGame类是游戏的核心控制类。负责创建骑手、食物、房子等对象;然后监听用户键盘输入、控制游戏逻辑、调整游戏状态、控制屏幕刷新。
class RunnerGame {
static RunnerGame instance; // 游戏单例
field Runner runner; // 骑手
field Food food; // 食物
field House house; // 配送地点
field int runnerX, runnerY; // 骑手当前位置
field int foodX, foodY; // 食物当前位置
field int houseX, houseY; // 房屋当前位置
field boolean picked; // 是否取到货
field int score; // 挣到的钱
field boolean exit; // 游戏结束
constructor RunnerGame new() {
do Screen.clearScreen();
let runnerX = 230;
let runnerY = 120;
let foodX = 100;
let foodY = 200;
let houseX = 400;
let houseY = 50;
let runner = Runner.new(runnerX, runnerY);
let house = House.new(houseX, houseY);
let food = Food.new(foodX, foodY);
let picked = false;
let score = 0;
let exit = false;
// 底部分数分数记录区
do Screen.drawRectangle(0, 238, 511, 240);
do Output.moveCursor(22,0);
do Output.printString("money: 0");
return this;
}
method void dispose() {
do runner.dispose();
do food.dispose();
do house.dispose();
do Memory.deAlloc(this);
return;
}
function void newInstance() {
let instance = RunnerGame.new();
return;
}
function RunnerGame getInstance() {
return instance;
}
// 开始游戏。用键盘控制骑手位置,先取货,再送货,然后获得奖励
method void run() {
var char key;
while (~exit) {
// 等待按下按键
while ((key = 0) & (~exit)) {
let key = Keyboard.keyPressed();
do Sys.wait(50);
}
do moveRunner(key);
// 等待按键松开
while ((~(key = 0)) & (~exit)) {
let key = Keyboard.keyPressed();
do Sys.wait(50);
}
do updateStatus();
do reDraw();
}
if (exit) {
do Output.moveCursor(1,23);
do Output.printString("Congratulations!");
}
return;
}
method void moveRunner(int key) {
// 左 = 130,上 = 131,右 = 132,下 = 133
if (key = 130) {
let runnerX = runnerX - 20;
} else {
if (key = 131) {
let runnerY = runnerY - 20;
} else {
if (key = 132) {
let runnerX = runnerX + 20;
} else {
if (key = 133) {
let runnerY = runnerY + 20;
}
}
}
}
// 防止越界
if (runnerX > 490) {
let runnerX = 490;
}
if (runnerX < 0) {
let runnerX = 0;
}
if (runnerY > 236) {
let runnerY = 236;
}
if (runnerY < 0) {
let runnerY = 0;
}
do runner.moveTo(runnerX, runnerY);
return;
}
method void updateStatus() {
// 取到食物
if ((Math.abs(foodX - runnerX) < 20) & (Math.abs(foodY - runnerY) < 20)) {
let picked = true;
do runner.setPicked(picked);
}
// 送到食物
if (picked & ((Math.abs(houseX - runnerX) < 20) & (Math.abs(houseY - runnerY) < 20))) {
let score = score + 30;
if (score > 100) {
let exit = true;
}
let picked = false;
do runner.setPicked(picked);
do newRound();
}
return;
}
// 完成一次配送,更新食物和房屋的位置
method void newRound() {
// 更新位置
let foodX = mod(foodX + houseX , 490);
let foodY = mod(foodY + houseY , 236);
let houseX = mod(foodY + houseX , 490);
let houseY = mod(houseX + foodY , 236);
do food.moveTo(foodX, foodY);
do house.moveTo(houseX, houseY);
return;
}
// 重新绘制
method void reDraw() {
do runner.show();
do house.show();
if (picked) {
do food.hide();
} else {
do food.show();
}
do Output.moveCursor(22,7);
do Output.printInt(score);
return;
}
// 补充一个取模的方法
method int mod(int x, int y) {
var int q;
let q = Math.divide(x, y);
return x - (q*y);
}
}
Runner,House,Food类负责表示个字的对象,维护对象位置信息,状态信息,并负责绘制自己的图形。
class Runner {
field int x, y; // 骑手位置
field int width, height; // 骑手宽高 20*20
field boolen picked; // 是否已取货
// 新创建一个骑手
constructor Runner new(int Ax, int Ay) {
let x = Ax;
let y = Ay;
let width = 20;
let height = 20;
let picked = false;
do show();
return this;
}
method void dispose() {
do Memory.deAlloc(this);
return;
}
// 在screen上展示骑手
method void show() {
do Screen.setColor(true);
do draw();
return;
}
// 抹掉当前在screen上展示的骑手
method void hide() {
do Screen.setColor(false);
do draw();
return;
}
/** 绘制房屋 */
method void draw() {
do Screen.drawRectangle(x, y + 9, x + 19, y + 10);
do Screen.drawCircle(x + 5, y + 15, 4);
do Screen.drawCircle(x + 15, y + 15, 4);
do Screen.drawLine(x + 15, y + 9, x + 15, y + 4);
do Screen.drawLine(x + 11, y + 4, x + 19, y + 4);
if (picked) {
do Screen.drawCircle(x + 4, y + 4, 3);
}
return;
}
method void setPicked(boolean Apicked) {
let picked = Apicked;
return;
}
method void moveTo(int Ax, int Ay) {
do hide(); //先抹掉当前骑手
let x = Ax;
let y = Ay;
do draw(); // 重新画骑手
return;
}
}
class Food {
field int x, y; // 食物位置
field int width, height; // 食物宽高 15*15
// 新创建一个食物
constructor Food new(int Ax, int Ay) {
let x = Ax;
let y = Ay;
let width = 15;
let height = 15;
do show();
return this;
}
method void dispose() {
...
}
// 在screen上展示食物
method void show() {
...
}
// 抹掉当前在screen上展示的食物
method void hide() {
...
}
/** 绘制食物 */
method void draw() {
...
}
method void moveTo(int Ax, int Ay) {
...
}
}
class House {
field int x, y; // 房屋位置
field int width, height; // 房屋宽高 20*20
// 新创建一个房屋
constructor House new(int Ax, int Ay) {
let x = Ax;
let y = Ay;
let width = 20;
let height = 20;
do show();
return this;
}
method void dispose() {
...
}
// 在screen上展示房屋
method void show() {
...
}
// 抹掉当前在screen上展示的房屋
method void hide() {
...
}
/** 绘制房屋 */
method void draw() {
...
}
method void moveTo(int Ax, int Ay) {
...
}
}
广告
