一、遊戲分析 相信大家對金山打字通、打字精靈等打字軟體非常熟悉,想當年剛接觸電腦時還靠它們的打字遊戲練習打字基本功。這章的遊戲DEMO就是一個打字小遊戲,當然,它很簡單,只是A~Z字母的打字練習小遊戲。遊戲的設計也不複雜,遊戲開始時先初始化下落字母的個數和每次下落字母的機率,隨著時間的進行,字母會從介面上方逐漸下落到介面底下,在這過程中你需要敲擊鍵盤上與介面下落的字母相對應的鍵位,如果鍵位的字母與下落的字母一致,則記錄打字正確數量,否則不記錄,無論如何,敲擊一次鍵盤記錄一下敲擊鍵盤數,當字母下落到介面底下時,字母停止下落,該字母被視為無效,相應地,也記錄一次敲擊數。正確率、敲擊數等資訊會在介面上顯示,遊戲還有倒計時,時間一到則被視為遊戲結束。
二、遊戲實現 先定義一個字母表,字母表的實現為: ///LetterTable類實現
using System;namespace Typing{ internal sealed class LetterTable { private static String[] LETTERS_TABLE = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" }; /// <summary> /// 擷取字母表長度 /// </summary> /// <returns></returns> public static Int32 getLength() { return LETTERS_TABLE.Length; } /// <summary> /// 根據索引擷取字母 /// </summary> /// <param name="index"></param> /// <returns></returns> public static String getLetter(Int32 index) { return LETTERS_TABLE[index]; } /// <summary> /// 根據字母擷取字母碼 /// </summary> /// <param name="letter"></param> /// <returns></returns> public static Int32 getLetterCode(String letter) { Int32 code = 65; for (Int32 i = 0; i < LETTERS_TABLE.Length; i++) { if (getLetter(i).Equals(letter)) { code = 65 + i; } } return code; } }}
///Letter類實現
using System;using CEngine;using CGraphics;namespace Typing{ internal class Letter { /// <summary> /// 字母 /// </summary> private String m_letter; /// <summary> /// 字母碼 /// </summary> private Int32 m_code; /// <summary> /// 字母背景色 /// </summary> private ConsoleColor m_backcolor; /// <summary> /// 字母前景色彩 /// </summary> private ConsoleColor m_fontcolor; /// <summary> /// 字母活動情況 /// </summary> private Boolean m_bAlive; /// <summary> /// 字母表單位置 /// </summary> private CPoint m_position; /// <summary> /// 隨機數 /// </summary> private static Random m_random = new Random(); /// <summary> /// 建構函式 /// </summary> public Letter() { } public String getLetter() { return this.m_letter; } public void setLetter(String letter) { this.m_letter = letter; } public Int32 getCode() { return this.m_code; } public void setCode(Int32 code) { this.m_code = code; } public Char getChar() { return (Char)this.m_code; } public ConsoleColor getBackcolor() { return this.m_backcolor; } public ConsoleColor getFontcolor() { return this.m_fontcolor; } public void setBackcolor(ConsoleColor color) { this.m_backcolor = color; } public void setFontcolor(ConsoleColor color) { this.m_fontcolor = color; } public Boolean getAlive() { return m_bAlive; } public void setAlive(Boolean bAlive) { this.m_bAlive = bAlive; } public CPoint getPosition() { return this.m_position; } public void setPosition(CPoint point) { this.m_position = point; } public void setPosition(Int32 x, Int32 y) { this.m_position.setX(x); this.m_position.setY(y); } /// <summary> /// 隨機得到一個字母 /// </summary> public void newLetter() { setLetter(LetterTable.getLetter(m_random.Next(0, 26))); setCode(LetterTable.getLetterCode(getLetter())); setBackcolor((ConsoleColor)m_random.Next(0, 16)); setFontcolor((ConsoleColor)(15 - (Int32)getBackcolor())); setPosition(m_random.Next(1, 30), -1); setAlive(false); } /// <summary> /// 繪製字母 /// </summary> /// <param name="draw"></param> public void draw(CDraw draw) { if (m_bAlive) { draw.setBackcolor(this.m_backcolor); draw.drawText(m_letter, m_position.getX(), m_position.getY(), 1, 1, this.m_fontcolor); } draw.setDrawSymbol(CSymbol.DEFAULT); draw.fillRect(m_position.getX(), m_position.getY() - 1, 1, 1, ConsoleColor.Black); } }}
定義一個字母管理類,用於管理所有下落的字母和配置字母的下落個數和每次下落字母的數量,字母管理類定義為:///LetterManager類實現
using System;using System.Collections.Generic;using CGraphics;namespace Typing{ internal sealed class LetterManager { private List<Letter> m_letters; /// <summary> /// 下落字母的個數 /// </summary> private Int32 m_fallNum; private Random m_random; private Int32 m_fallRate; public LetterManager(Int32 num, Int32 rate) { this.m_random = new Random(); this.m_fallNum = num; this.m_fallRate = rate; this.m_letters = new List<Letter>(); for (Int32 i = 0; i < m_fallNum; i++) { Letter letter = new Letter(); letter.newLetter(); this.m_letters.Add(letter); } } public List<Letter> getLetters() { return this.m_letters; } public Int32 getFallNum() { return this.m_fallNum; } public Int32 getFallRate() { return this.m_fallRate; } public void setFallRate(Int32 rate) { if (rate < 0) { this.m_fallRate = 1; return; } this.m_fallRate = rate; } public void addFallNum(Int32 num) { if (num <= 0) { return; } this.m_fallNum += num; for (Int32 i = 0; i < num; i++) { Letter letter = new Letter(); letter.newLetter(); this.m_letters.Add(letter); } } public void draw(CDraw draw) { for (Int32 i = 0; i < m_letters.Count; i++) { m_letters[i].draw(draw); } } }}
最後為遊戲類,實現遊戲的邏輯,遊戲類實現為:///TypingGame類實現
using System;using System.Collections.Generic;using CEngine;using CGraphics;namespace Typing{ public sealed class TypingGame : CGame { private LetterManager m_letBuilder; /// <summary> /// 打字正確個數 /// </summary> private float m_rightCount; /// <summary> /// 打字個數 /// </summary> private float m_typingCount; private CDraw m_draw; /// <summary> /// 倒計時 /// </summary> private Int32 m_countDown; private Int32 m_lastTime; /// <summary> /// 下落速度控制 /// </summary> private Int32 m_fallTime; /// <summary> /// 是否在打字 /// </summary> private Boolean m_isType; private Random m_random; protected override void gameInit() { setTitle("控制台遊戲之——鍵盤熟練工v1.0"); m_letBuilder = new LetterManager(20, 2); setCursorVisible(false); setUpdateRate(40); m_rightCount = 0f; m_typingCount = 0f; m_countDown = 200; m_fallTime = 10; m_isType = false; m_random = new Random(); m_draw = base.getDraw(); m_draw.setDrawSymbol(CSymbol.RECT_SOLID); m_draw.drawRect(0, 0, 31, 25, ConsoleColor.White); m_draw.setDrawSymbol(CSymbol.DEFAULT); m_draw.fillRect(1, 0, 29, 1, ConsoleColor.Black); m_draw.setDrawSymbol(CSymbol.RHOMB_SOLID); m_draw.drawRect(31, 0, 9, 13, ConsoleColor.DarkYellow); m_draw.setDrawSymbol(CSymbol.RHOMB_SOLID); m_draw.drawRect(31, 12, 9, 13, ConsoleColor.DarkYellow); m_draw.drawText("倒計時:", 65, 2, ConsoleColor.Red); m_draw.drawText("正確率:", 65, 4, ConsoleColor.Green); m_draw.drawText("擊鍵數:", 65, 6, ConsoleColor.Green); m_draw.drawText("FPS:", 65, 8, ConsoleColor.Green); m_draw.drawText("Rate:", 65, 10, ConsoleColor.Green); m_draw.drawText("操作:鍵盤A--Z鍵,根據下落的字母打擊鍵盤對應的鍵位,正確率體現你的鍵盤操作熟悉程度。", new CRect(33, 14, 5, 10), ConsoleColor.DarkGreen); } protected override void gameDraw(CGraphics.CDraw draw) { m_letBuilder.draw(draw); draw.setBackcolor(ConsoleColor.Black); draw.drawText(m_countDown.ToString("000"), 73, 2, ConsoleColor.Red); if (m_typingCount != 0) { draw.drawText(((m_rightCount / m_typingCount) * 100).ToString("000") + "%", 73, 4, ConsoleColor.Red); } else { draw.drawText("0%", 73, 4, ConsoleColor.Red); } draw.drawText(m_typingCount.ToString("000"), 73, 6, ConsoleColor.Red); draw.drawText(getFPS().ToString(), 73, 8, ConsoleColor.Blue); draw.drawText(getUpdateRate().ToString(), 73, 10, ConsoleColor.Blue); } protected override void gameLoop() { if (m_fallTime == 0) { List<Letter> letters = m_letBuilder.getLetters(); for (Int32 i = 0; i < letters.Count; i++) { //每個字母按幾率下落 if (m_random.Next(0, m_letBuilder.getFallNum() * m_letBuilder.getFallRate()) == i) { letters[i].setAlive(true); } //字母下落 if (letters[i].getAlive()) { letters[i].setPosition(letters[i].getPosition().getX(), letters[i].getPosition().getY() + 1); } //字母下落到地面 if (letters[i].getPosition().getY() >= getClientRect().getHeight()-1) { letters[i].newLetter(); m_typingCount++; } } m_fallTime = 5; } m_fallTime--; if (Environment.TickCount - m_lastTime > 1000) { m_lastTime = Environment.TickCount; m_countDown--; if (m_countDown == 0) { setGameOver(true); } } } protected override void gameExit() { m_letBuilder = null; base.getDraw().clear(ConsoleColor.Black); base.getDraw().drawText("Game Over!", 25, 10, ConsoleColor.Red); base.getDraw().drawText("Copyright (c) D-Zone Studio", 40, 10, ConsoleColor.White); Console.ReadLine(); } protected override void gameKeyDown(CKeyboardEventArgs e) { if (!m_isType) { List<Letter> letters = m_letBuilder.getLetters(); for (Int32 i = 0; i < letters.Count; i++) { if (letters[i].getAlive()) { //是否打對字母 if (letters[i].getChar().ToString() == e.getKey().ToString()) { base.update(new CRect(letters[i].getPosition().getX(),letters[i].getPosition().getY(),1,1)); letters[i].newLetter(); m_rightCount++; break; } } } m_typingCount++; if (e.getKey() == CKeys.Escape) { setGameOver(true); } m_isType = true; } } protected override void gameKeyUp(CKeyboardEventArgs e) { m_isType = false; } }}
從前面和現在這個遊戲可以看到,不同遊戲除了邏輯上設計上的不同之外,其他很多部分都是通用的,我們沒必要每次寫個小遊戲都要做重複的編碼工作,這也是寫這個小遊戲架構的原因及必要性。
最後我們來欣賞下我們的勞動成果:試玩連結:http://download.csdn.net/detail/hwenycocodq520/4630387四、結語 實話說,這個遊戲DEMO實現得比較倉促,代碼寫得比較淩亂,但都是些簡單的邏輯,相信大家都能看得明白。