㈠ 如何用C語言編一個俄羅斯方塊
游戲界面預覽:
菜單預覽:
自定義每個小方塊顏色功能界面:
游戲主要有四部分組成:Square類,Block類,gameField類,游戲引擎
Square類:
這個類描述的對象是組成大方塊中的每個小正方形實體。
類設計:
class Square
{
public Point location; //小方塊的坐標
public Size size; //小方塊大小
public Color foreColor; //小方塊前景色
public Color backColor; //小方塊背景色
public Square(Size initSize,Color initForeColor,Color initBackColor) //構造函數
{ ……}
public void Draw(System.IntPtr winHandle) //在指定設備上畫方塊
{ …… }
public void Erase(System.IntPtr winHandle)//擦除方塊
{ …… }
}
Block類:
這個類描述的對象是某一個大方塊的實體。每個大方塊由四個小正方形組成,一共有7種組合方式。這個類需要實現一個大方塊實體所有的屬性和動作。包括:方塊的形狀,位置,方塊左移,右移,下移,旋轉等。
類設計:
class Block
{
public Square square1; //組成block的四個小方塊
public Square square2;
public Square square3;
public Square square4; private const int squareSize = GameField.SquareSize; //小方塊的邊長
public enum BlockTypes
{
undefined = 0,
square = 1,
line = 2,
J = 3,
L = 4,
T = 5,
Z = 6,
S = 7
};//一共有7種形狀
public BlockTypes blockType; //方塊的形狀
//七個小方塊的顏色數組
private Color foreColor;
private Color backColor;
//方塊的方向
public enum RotateDirections
{
North = 1,
East = 2,
South = 3,
West = 4
};
public RotateDirections myRotation = RotateDirections.North;
public Block(Point thisLocation,BlockTypes bType)
{ ……}
//含有自定義顏色的重載
public Block(Point thisLocation, BlockTypes bType,Color fc,Color bc)
{ ……} /*畫方塊*/
public void Draw(System.IntPtr winHandle)
{…… }
/*擦方塊*/
public void Erase(System.IntPtr winHandle)
{…… } /*移動*/
public bool down()
{……}
public bool left()
{……}
public bool right()
{……}
/*旋轉block*/
public void Rotate()
{……}
/*檢測是否到頂*/
public int Top()
{……}
}
GameField類:
這個類描述的對象是游戲場景實體,包括場景的背景色,大小,方塊是否還可以移動,以及場景中填滿一行的檢測等。
類設計:
class GameField
{
public const int width = 20; //場景的寬,以方塊個數為單位
public const int height = 30;
public const int SquareSize = 15; //每個四分之一小方塊的邊長
public static Color BackColor; //場景的背景色
public static System.IntPtr winHandle; //場景的handle
public static Color[] BlockForeColor ={ Color.Blue, Color.Beige, Color.DarkKhaki, Color.DarkMagenta, Color.DarkOliveGreen, Color.DarkOrange, Color.DarkRed };
public static Color[] BlockBackColor ={ Color.LightCyan, Color.DarkSeaGreen, Color.Beige, Color.Beige, Color.Beige, Color.Beige, Color.Beige };
public static bool isChanged=false; //設置是否被更改的標志位
public static SoundPlayer sound = new SoundPlayer(); //播放聲音 public static Square[,] arriveBlock = new Square[width, height]; //保存已經不能再下落了的方塊
public static int[] arrBitBlock=new int[height]; //位數組:當某個位置有方塊時,該行的該位為1
private const int bitEmpty = 0x0; //0000 0000 0000 0000 0000
private const int bitFull = 0xFFFFF; //1111 1111 1111 1111 1111 /*檢測某個位置是否為空*/
public static bool isEmpty(int x, int y)
{……}
/*將方塊停住*/
public static void stopSquare(Square sq, int x, int y)
{……}
/*檢測行是否滿
* 返回:成功消除的行數和 (方便統計分數)
*/
public static int CheckLines()
{ ……}
/*播放聲音*/
public static void PlaySound(string soundstr)
{……}
/*重畫*/
public static void Redraw()
{ …… }
//結束
}
游戲引擎:
游戲引擎正如其名,就像一個發動機一樣讓游戲不間斷運行。本游戲中就是讓方塊以一定的速度下落。並響應鍵盤事件,實行左右移動,和向下加速功能。(代碼見源碼)
聲音播放:
音效是游戲不可缺少的一部分。在.Net2.0中已經提供了一個類來播放聲音。在using System.Media;命名空間。
本游戲中播放聲音的代碼如下:(在 GameField類中)
using System.Media;
public static SoundPlayer sound = new SoundPlayer();
/*播放聲音*/
public static void PlaySound(string soundstr)
{
switch (soundstr)
{
case "FinishOneLine": //消除一行的聲音
if (!File.Exists("FinishOneLine.wav")) return;
sound.SoundLocation = "FinishOneLine.wav";
break;
case "CanNotDo": //當無法操作時
if (!File.Exists("CanNotDo.wav")) return;
sound.SoundLocation = "CanNotDo.wav";
break;
}
sound.Play();
}
要播放的時候調用PlaySound()方法即可。
其實步驟很簡單,先引用System.Media空間,然後創建一個SoundPlayer 對象,用SoundLocation 屬性設置聲音文件的地址,然後調用Play()方法即可播放。不過注意,這個類可以播放的聲音格式只有Wav文件。
保存游戲設置:
在游戲中經常要保存用戶自定義的設置。本游戲通過寫進ini文件來保存。
主要代碼如:
/*載入窗體時從配置文件Setting.ini中讀取游戲設置*/
private void getSettings()
{
if (!File.Exists("Setting.ini"))
return;
FileStream fs = new FileStream("Setting.ini", FileMode.OpenOrCreate, FileAccess.ReadWrite);
StreamReader sr = new StreamReader(fs);
string line1=sr.ReadLine();
string line2=sr.ReadLine();
string line3=sr.ReadLine();
if (line1 != null && line1.Split('=').Length > 1)
{
GameField.BackColor = Color.FromArgb(int.Parse(line1.Split('=')[1]));
picBackGround.BackColor = GameField.BackColor;
}
if (line2 != null && line2.Split('=').Length > 1)
GameField.BlockForeColor = strToColor(line2.Split('=')[1]);
if (line3 != null && line3.Split('=').Length > 1)
GameField.BlockBackColor = strToColor(line3.Split('=')[1]);
sr.Close();
fs.Close();
}
/*如果游戲設置被更改,將新的設置保存到Setting.ini*/
private void saveSettings()
{
FileStream fs = new FileStream("Setting.ini", FileMode.Create, FileAccess.ReadWrite);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine("GameFieldColor="+GameField.BackColor.ToArgb());
sw.WriteLine("BlockFroeColor=" + colorToStr(GameField.BlockForeColor));
sw.WriteLine("BlockBackColor=" + colorToStr(GameField.BlockBackColor));
sw.Flush();
sw.Close();
fs.Close();
}
要源碼+QQ348199903
㈡ vb6.0如何編寫俄羅斯方塊
using System;
using System.Drawing;
using Microsoft.Win32;
namespace AnotherBlock
{
/// <summary>
/// Represents a Tetris game engine.
/// </summary>
public class Game
{
/// <summary>
/// Constant with the image width of the block unit (in pixels).
/// </summary>
public const int BlockImageWidth = 21;
/// <summary>
/// Constant with the image height of the block unit (in pixels).
/// </summary>
public const int BlockImageHeight = 21;
/// <summary>
/// Constant with the playing field width (in block units).
/// </summary>
public const int PlayingFieldWidth = 10;
/// <summary>
/// Constant with the playing field height (in block units).
/// </summary>
public const int PlayingFieldHeight = 20;
/// <summary>
/// Constante with the number of lines for each level.
/// </summary>
public const int LevelEveryLines = 12;
/// <summary>
/// Private attribute that holds the current game score.
/// </summary>
private int score = 0;
/// <summary>
/// Private attribute that holds the current game level.
/// </summary>
private short level = 1;
/// <summary>
/// Private attribute that holds the current number of completed lines.
/// </summary>
private int lines = 0;
/// <summary>
/// Private attribute that holds the current game state.
/// </summary>
private GameState gameState;
/// <summary>
/// Private attribute that holds the level where the game started.
/// </summary>
private short startLevel = 1;
/// <summary>
/// Private attribute that holds the current game pile.
/// </summary>
private Brick[,] pile = new Brick[(PlayingFieldWidth + 1), (PlayingFieldHeight + 1)];
/// <summary>
/// Private attribute that holds the current block.
/// </summary>
private Block currentBlock = new Block();
/// <summary>
/// Private attribute that holds the next block.
/// </summary>
private Block nextBlock = new Block();
/// <summary>
/// Class constructor that creates a game.
/// </summary>
public Game()
{
// Clears the game pile.
ClearPile();
}
/// <summary>
/// Class constructor that creates a game in a given level.
/// </summary>
/// <param name="level">The level where the game should start.</param>
public Game(short level)
{
// Sets the level attribute to the game level where the game should start.
this.level = level;
// Sets the startLevel attribute to the game level where the game should start.
startLevel = level;
// Clears the game pile.
ClearPile();
}
/// <summary>
/// Readonly property that holds the score of the current game.
/// </summary>
public int Score
{
get
{
// Returns the value in the score attribute.
return score;
}
}
/// <summary>
/// Readonly property that holds the level of the current game.
/// </summary>
public short Level
{
get
{
// Returns the value in the level attribute.
return level;
}
}
/// <summary>
/// Readonly property that holds the number of complete lines in the current game.
/// </summary>
public int Lines
{
get
{
// Returns the value in the lines attribute.
return lines;
}
}
/// <summary>
/// Property that holds and sets the current game state.
/// </summary>
/// <remarks>
/// The game state can be "Running", "Paused" or "Over".
/// </remarks>
public GameState GameState
{
get
{
// Returns the value in the gameState attribute.
return gameState;
}
set
{
// Checks if the current game state is "Over", and if the value to change is not "Over".
if ((gameState == GameState.Over) && (value != GameState.Over))
{
// The current game state is "Over", and it's changing to something else than "Over".
// Resets the score, level and lines.
score = 0;
level = startLevel;
lines = 0;
// Creates a new current block, and a new next block.
currentBlock = new Block();
nextBlock = new Block();
// Clears the game pile.
ClearPile();
}
// Sets the gameState attribute to the value.
gameState = value;
}
}
/// <summary>
/// Method that moves the current block down one position.
/// </summary>
/// <returns>True if there was a hit on the ground or on the pile, false if there wasn't.</returns>
public bool MoveCurrentBlockDown()
{
// Creates a "hit" flag, to check if the block has hit the pile or the ground.
bool hit = false;
// Increases the Top of the current block.
currentBlock.Top++;
// Checks if the current block has hit the ground.
// COLLISION DETECTION
if ((currentBlock.Top + currentBlock.Height) > PlayingFieldHeight)
{
// Current block has hit the ground.
// Sets the "hit" flag to "true".
hit = true;
}
else
{
// Checks if the current block has hit the pile.
// COLLISION DETECTION
for(int i = 0; i < currentBlock.Width; i++)
{
for(int j = 0; j < currentBlock.Height; j++)
{
int fx, fy;
fx = currentBlock.Left + i;
fy = currentBlock.Top + j;
if ((currentBlock.Shape[i, j].Filled == true) && (pile[fx, (fy + 1)].Filled == true))
{
// Current block has hit the pile.
// Sets the "hit" flag to "true".
hit = true;
}
}
}
}
// Checks if there was a hit.
if (hit)
{
// There was a hit.
// Puts the current block in the pile.
MoveBlockToPile();
// Checks if the current game state is not "Over".
if (this.GameState != GameState.Over)
{
// Current game state is not "Over".
// Creates a new block.
CreateNewBlock();
}
}
// Returns if there was a hit or not.
return hit;
}
/// <summary>
/// Method that moves the current block down until there is a hit.
/// </summary>
public void ()
{
// Moves the current block down until it has a hit.
while(!MoveCurrentBlockDown());
}
/// <summary>
/// Method that rotates the current block.
/// </summary>
/// <param name="clockwise">True if the block will be rotated clockwise, false if counterclockwise.</param>
public void RotateCurrentBlock(bool clockwise)
{
// Creates a "canRotate" flag, to check if the block can be rotated.
bool canRotate = true;
// Rotates the current block.
// This should be different. There should be an easy way to check FIRST if the block could
// be rotated, and then rotate it. I'll study this later.
currentBlock.Rotate(clockwise);
// Checks if the current block could be rotated.
// COLLISION DETECTION
for(int i = 0; i < currentBlock.Width; i++)
{
for(int j = 0; j < currentBlock.Height; j++)
{
int fx, fy;
fx = currentBlock.Left + i;
fy = (currentBlock.Top + 1) + j;
if ((currentBlock.Shape[i, j].Filled == true) && (pile[fx, fy].Filled == true))
{
// Current block can't be rotated.
// Sets the "canRotate" flag to "false".
canRotate = false;
}
}
}
// Checks if the block can't be rotated.
if (!canRotate)
{
// Block can't be rotated.
// Rotates the block back to its first position.
currentBlock.Rotate(!clockwise);
}
}
/// <summary>
/// Method that moves the current block to the right or to the left.
/// </summary>
/// <param name="left">True if the block will be moved to the left, false if to the right.</param>
public void MoveCurrentBlockSide(bool left)
{
// Creates a "canMove" flag, to check if the block can be moved to the sides.
bool canMove = true;
// Checks if the block is to be moved to the left.
if (left)
{
// The block is to be moved to the left.
// Checks if the block is not already at the most left of the playing field.
if (currentBlock.Left > 0)
{
// Block is not at the most left of the playing field.
// Checks if the current block can move to the left.
// COLLISION DETECTION
for(int i = 0; i < currentBlock.Width; i++)
{
for(int j = 0; j < currentBlock.Height; j++)
{
int fx, fy;
fx = currentBlock.Left + i;
fy = (currentBlock.Top + 1) + j;
if ((currentBlock.Shape[i, j].Filled == true) && (pile[(fx - 1), fy].Filled == true))
{
// Current block can't move to the left.
// Sets the "canMove" flag to "false".
canMove = false;
}
}
}
// Checks if the block can be moved to the left.
if (canMove)
{
// Block can be moved to the left.
// Moves the block to the left.
currentBlock.Left--;
}
}
}
else
{
// The block is not to be moved to the left (it is to be moved to the right).
// Checks if the block is not already at the most right of the playing field.
if ((currentBlock.Left + currentBlock.Width) < PlayingFieldWidth)
{
// Block is not at the most right of the playing field.
// Checks if the current block can move to the right.
// COLLISION DETECTION
for(int i = 0; i < currentBlock.Width; i++)
{
for(int j = 0; j < currentBlock.Height; j++)
{
int fx, fy;
fx = currentBlock.Left + i;
fy = (currentBlock.Top + 1) + j;
if ((currentBlock.Shape[i, j].Filled == true) && (pile[(fx + 1), fy].Filled == true))
{
// Current block can't move to the right.
// Sets the "canMove" flag to "false".
canMove = false;
}
}
}
// Checks if the block can be moved to the right.
if (canMove)
{
// Block can be moved to the right.
// Moves the block to the right.
currentBlock.Left++;
}
}
}
}
/// <summary>
/// Method that draws the pile in a surface.
/// </summary>
/// <param name="drawingSurface">The graphics surface where the pile will be drawn.</param>
public void DrawPile(Graphics drawingSurface)
{
// Runs through the playing field Width.
for (int i = 0; i < (PlayingFieldWidth + 1); i++)
{
// Runs through the playing field Height.
for (int j = 0; j < (PlayingFieldHeight + 1); j++)
{
// Checks if the current brick of the pile is set to be solid.
if (pile[i, j].Filled == true)
{
// Current brick of the pile is set to be solid.
// Creates a rectangle in the right position of this brick.
Rectangle rect = new Rectangle(i * BlockImageWidth, (j - 1) * BlockImageHeight, BlockImageWidth, BlockImageHeight);
// Draws the block image in the just created rectangle.
drawingSurface.DrawImage(pile[i, j].BrickImage, rect);
}
}
}
}
/// <summary>
/// Method that draws the current block in a surface.
/// </summary>
/// <param name="drawingSurface">The graphics surface where the current block will be drawn.</param>
public void DrawCurrentBlock(Graphics drawingSurface)
{
// Checks if there is a current block.
if (currentBlock != null)
{
// There is a current block.
// Draws the current block in the drawing surface.
currentBlock.Draw(drawingSurface);
}
}
/// <summary>
/// Method that draws the next block in a surface.
/// </summary>
/// <param name="drawingSurface">The graphics surface where the current block will be drawn.</param>
public void DrawNextBlock(Graphics drawingSurface)
{
// Checks if there is a next block.
if (nextBlock != null)
{
// There is a next block.
// Saves the current Left and Top properties of the next block.
short currentLeft = nextBlock.Left;
short currentTop = nextBlock.Top;
// Changes the current Left and Top properties of the next block, so they can be shown
// in the center of a drawing surface that has a size of 6x6 blocks.
nextBlock.Left = (short)((6 - nextBlock.Width) / 2);
nextBlock.Top = (short)((6 - nextBlock.Height) / 2);
// Draws the next block in the drawing surface.
nextBlock.Draw(drawingSurface);
// Retrieves the previously saved Left and Top properties, and put them back in the next block.
nextBlock.Left = currentLeft;
nextBlock.Top = currentTop;
}
}
/// <summary>
/// Private method that clears the current game pile.
/// </summary>
private void ClearPile()
{
// Runs through the playing field Width.
for(int i = 0; i < (PlayingFieldWidth + 1); i++)
{
// Runs through the playing field Height.
for(int j = 0; j < (PlayingFieldHeight + 1); j++)
{
// Clears the current brick of the pile.
pile[i, j].Filled = false;
}
}
}
/// <summary>
/// Private method that creates a new current block by getting it from the next block,
/// and creates a new random next block.
/// </summary>
private void CreateNewBlock()
{
// Checks if there is a next block.
if (this.nextBlock != null)
{
// There is a next block.
// Sets the current block to the next block.
currentBlock = nextBlock;
}
else
{
// There isn't a next block.
// Sets the current block as a new random block.
currentBlock = new Block();
}
// Sets the next block as a new random block.
nextBlock = new Block();
}
/// <summary>
/// Private method that moves the current block to the game pile.
/// While moving the block to the pile, it checks if there are complete lines, and count them, in
/// order to update the score, the lines and the level. It also checks for game over.
/// </summary>
private void MoveBlockToPile()
{
// Runs through the current block Width.
for(int i = 0; i < currentBlock.Width; i++)
{
// Runs through the current block Height.
for(int j = 0; j < currentBlock.Height; j++)
{
// Converts the current brick position the a playing field position.
int fx, fy;
fx = currentBlock.Left + i;
fy = currentBlock.Top + j;
// Checks if the current brick is solid.
if (currentBlock.Shape[i, j].Filled == true)
{
// The current brick is solid.
// Moves the current brick to the pile.
pile[fx, fy].Filled = true;
pile[fx, fy].BrickImage = currentBlock.Shape[i, j].BrickImage;
}
}
}
// Checks for complete lines.
CheckForLines();
// Checks for game over.
CheckForGameOver();
}
/// <summary>
/// Private method that checks the pile for complete lines.
/// </summary>
/// <returns>The number of found lines.</returns>
private int CheckForLines()
{
// Creates a variable that will hold the number of lines found.
int numLines = 0;
// Creates a variable that will hold the number of the complete lines found.
int[] completeLines = new int[PlayingFieldHeight];
// Runs through the playing field lines.
for (int j = PlayingFieldHeight; j > 0; j--)
{
// Checks if there is a complete line.
bool fullLine = true;
for (int i = 0; i < PlayingFieldWidth; i++)
{
if (pile[i, j].Filled == false)
{
fullLine = false;
break;
}
}
// Checks if there was a complete line.
if (fullLine)
{
// There was a complete line.
// Increases the number of complete lines found.
numLines++;
// Pauses the game so no block will come down while clearing the complete line.
this.GameState = GameState.Paused;
// Holds the number of the complete line found.
completeLines[numLines] = j;
// Sets the game state to "Running" again, to release the game.
this.GameState = GameState.Running;
}
}
// Checks if there were any complete lines.
if (numLines > 0)
{
// There were complete lines.
// Runs through all the complete lines, and clears them.
for(int i = 1; i <= numLines; i++)
{
// Clear a complete line.
ClearLine((completeLines[i] + (i - 1)));
}
// Updates the game score, lines and level.
score += 5 * (numLines * (numLines + 1));
lines += numLines;
level = (short)((lines / LevelEveryLines) + startLevel);
}
// Returns the number of complete lines.
return numLines;
}
/// <summary>
/// Private method that checks the pile for game over.
/// </summary>
private void CheckForGameOver()
{
// Checks if the top of the current block is on the top of the pile.
if (currentBlock.Top == 1)
{
// Current block is on the top the the pile.
// Sets the game state to "Over".
this.GameState = GameState.Over;
}
}
/// <summary>
/// Private method that clears a line from the pile.
/// </summary>
/// <param name="lineNumber">The number of the line to be cleared.</param>
private void ClearLine(int lineNumber)
{
// Runs through all the lines, from the line to be cleared up.
for (int j = lineNumber; j > 0; j--)
{
// Runs through all the bricks in one line.
for (int i = 0; i < PlayingFieldWidth; i++)
{
// Move the current brick down.
pile[i, j] = pile[i, (j - 1)];
}
}
// Runs through the top line bricks.
for (int i = 0; i < PlayingFieldWidth; i++)
{
// Sets the current brick to empty.
pile[i, 0].Filled = false;
}
}
}
}
這是其中之一最重要的部分,要全部代碼給我發郵件
[email protected]
㈢ 如何用java編寫出一個俄羅斯方塊小程序
packagecom.test.games;
importjava.awt.Graphics;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
importjava.awt.event.KeyEvent;
importjava.awt.event.KeyListener;
importjavax.swing.JFrame;
importjavax.swing.JMenu;
importjavax.swing.JMenuBar;
importjavax.swing.JMenuItem;
importjavax.swing.JOptionPane;
importjavax.swing.JPanel;
importjavax.swing.Timer;
{
publicTetris(){
Tetrisbloka=newTetrisblok();
addKeyListener(a);
add(a);
}
publicstaticvoidmain(String[]args){
Tetrisframe=newTetris();
JMenuBarmenu=newJMenuBar();
frame.setJMenuBar(menu);
JMenugame=newJMenu("游戲");
JMenuItemnewgame=game.add("新游戲");
JMenuItempause=game.add("暫停");
JMenuItemgoon=game.add("繼續");
JMenuItemexit=game.add("退出");
JMenuhelp=newJMenu("幫助");
JMenuItemabout=help.add("關於");
menu.add(game);
menu.add(help);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(220,275);
frame.setTitle("Tetris內測版");
//frame.setUndecorated(true);
frame.setVisible(true);
frame.setResizable(false);
}
}
//創建一個俄羅斯方塊類
{
//blockType代表方塊類型
//turnState代表方塊狀態
privateintblockType;
privateintscore=0;
privateintturnState;
privateintx;
privateinty;
privateinti=0;
intj=0;
intflag=0;
//定義已經放下的方塊x=0-11,y=0-21;
int[][]map=newint[13][23];
//方塊的形狀第一組代表方塊類型有S、Z、L、J、I、O、T7種第二組代表旋轉幾次第三四組為方塊矩陣
privatefinalintshapes[][][]=newint[][][]{
//i
{{0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},
{0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},
{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0}},
//s
{{0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
{0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0}},
//z
{{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},
{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0}},
//j
{{0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0},{1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
{1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0},
{1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0}},
//o
{{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0}},
//l
{{1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0},{1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0},
{0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0}},
//t
{{0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0},{0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
{1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0},
{0,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0}}};
//生成新方塊的方法
publicvoidnewblock(){
blockType=(int)(Math.random()*1000)%7;
turnState=(int)(Math.random()*1000)%4;
x=4;
y=0;
if(gameover(x,y)==1){
newmap();
drawwall();
score=0;
JOptionPane.showMessageDialog(null,"GAMEOVER");
}
}
//畫圍牆
publicvoiddrawwall(){
for(i=0;i<12;i++){
map[i][21]=2;
}
for(j=0;j<22;j++){
map[11][j]=2;
map[0][j]=2;
}
}
//初始化地圖
publicvoidnewmap(){
for(i=0;i<12;i++){
for(j=0;j<22;j++){
map[i][j]=0;
}
}
}
//初始化構造方法
Tetrisblok(){
newblock();
newmap();
drawwall();
Timertimer=newTimer(1000,newTimerListener());
timer.start();
}
//旋轉的方法
publicvoidturn(){
inttempturnState=turnState;
turnState=(turnState+1)%4;
if(blow(x,y,blockType,turnState)==1){
}
if(blow(x,y,blockType,turnState)==0){
turnState=tempturnState;
}
repaint();
}
//左移的方法
publicvoidleft(){
if(blow(x-1,y,blockType,turnState)==1){
x=x-1;
}
;
repaint();
}
//右移的方法
publicvoidright(){
if(blow(x+1,y,blockType,turnState)==1){
x=x+1;
}
;
repaint();
}
//下落的方法
publicvoiddown(){
if(blow(x,y+1,blockType,turnState)==1){
y=y+1;
delline();
}
;
if(blow(x,y+1,blockType,turnState)==0){
add(x,y,blockType,turnState);
newblock();
delline();
}
;
repaint();
}
//是否合法的方法
publicintblow(intx,inty,intblockType,intturnState){
for(inta=0;a<4;a++){
for(intb=0;b<4;b++){
if(((shapes[blockType][turnState][a*4+b]==1)&&(map[x+b+1][y+a]==1))
||((shapes[blockType][turnState][a*4+b]==1)&&(map[x+b+1][y+a]==2))){
return0;
}
}
}
return1;
}
//消行的方法
publicvoiddelline(){
intc=0;
for(intb=0;b<22;b++){
for(inta=0;a<12;a++){
if(map[a][b]==1){
c=c+1;
if(c==10){
score+=10;
for(intd=b;d>0;d--){
for(inte=0;e<11;e++){
map[e][d]=map[e][d-1];
}
}
}
}
}
c=0;
}
}
//判斷你掛的方法
publicintgameover(intx,inty){
if(blow(x,y,blockType,turnState)==0){
return1;
}
return0;
}
//把當前添加map
publicvoidadd(intx,inty,intblockType,intturnState){
intj=0;
for(inta=0;a<4;a++){
for(intb=0;b<4;b++){
if(map[x+b+1][y+a]==0){
map[x+b+1][y+a]=shapes[blockType][turnState][j];
}
;
j++;
}
}
}
//畫方塊的的方法
publicvoidpaintComponent(Graphicsg){
super.paintComponent(g);
//畫當前方塊
for(j=0;j<16;j++){
if(shapes[blockType][turnState][j]==1){
g.fillRect((j%4+x+1)*10,(j/4+y)*10,10,10);
}
}
//畫已經固定的方塊
for(j=0;j<22;j++){
for(i=0;i<12;i++){
if(map[i][j]==1){
g.fillRect(i*10,j*10,10,10);
}
if(map[i][j]==2){
g.drawRect(i*10,j*10,10,10);
}
}
}
g.drawString("score="+score,125,10);
g.drawString("抵制不良游戲,",125,110);
g.drawString("拒絕盜版游戲。",125,170);
// g.drawString("注意自我保護,",125,90);
// g.drawString("謹防受騙上當。",125,110);
// g.drawString("適度游戲益腦,",125,130);
// g.drawString("沉迷游戲傷身。",125,150);
// g.drawString("合理安排時間,",125,170);
// g.drawString("享受健康生活。",125,190);
}
//鍵盤監聽
publicvoidkeyPressed(KeyEvente){
switch(e.getKeyCode()){
caseKeyEvent.VK_DOWN:
down();
break;
caseKeyEvent.VK_UP:
turn();
break;
caseKeyEvent.VK_RIGHT:
right();
break;
caseKeyEvent.VK_LEFT:
left();
break;
}
}
//無用
publicvoidkeyReleased(KeyEvente){
}
//無用
publicvoidkeyTyped(KeyEvente){
}
//定時器監聽
{
publicvoidactionPerformed(ActionEvente){
repaint();
if(blow(x,y+1,blockType,turnState)==1){
y=y+1;
delline();
}
;
if(blow(x,y+1,blockType,turnState)==0){
if(flag==1){
add(x,y,blockType,turnState);
delline();
newblock();
flag=0;
}
flag=1;
}
;
}
}
}
㈣ 俄羅斯方塊怎麼做(要思想)
不要留空的
㈤ scratch 2.0俄羅斯方塊如何編
那還得要了解你的scratch基礎,如果你基礎夠好的話,我為你編一個,你就1比1復制就好了~(要會自定義方塊,列表,變數,等90%積木塊)
㈥ 一個簡單的c語言寫的俄羅斯方塊程序
1、考慮怎麼存儲俄羅斯方塊
俄羅斯方塊的形狀一共有19種類型,如果拿數組來表示的話,可能會比較會浪費空間(網上有很多實現代碼)
考慮到每種方塊形狀的范圍是4 *4的小方塊,用 字模點陣的方式來存儲,即設置一個4行4列的數組,元素置1即代表這個位置有小
方塊,元素置0即代表這個位置無小方塊,這個整個的4*4的數組組成俄羅斯方塊的形狀。
1000
1000
1100
0000
上述4*4來表示L形狀的方塊。
4*4 =16 bit 正好為short類型,所以每一個方塊可以用一個short類型的數據來表示。
我們把俄羅斯方塊點陣的數位存在rockArray中,我們可以事先把這19種方塊的字模點陣自己轉化成十六進制,然後在rockArray數組的初始化時賦值進去。
但是這種方式擴展性不好,每當有一種新方塊時需要改動,
所以可以寫一個配置文件來表示19種方塊。(RockShape.ini)
@###@###@@######1234
從配置文件中讀取方塊的類型的代碼在(Init.h的ReadRock函數中)在下面3中解釋下代碼如何實現
2如何畫出方塊
可以使用EasyX庫來畫出簡單的圖形,
EasyX庫是在VC下實現TC的簡單繪圖功能的一個庫,這個庫很容易學會(直接 網路EasyX庫,裡面有詳細的教程)
那麼如何畫出方塊,方塊已經存儲到一個short類型中了
從short中讀取出,可以用一個掩碼mask = 1來與short的每個bit位相與,結果為1,則畫出一個小方塊;
函數聲明:
void DisplayRock(int rockIdx, RockLocation_t* LocatePtr, bool displayed)1
參數1:表示在數組中的下標,取出short類型的方塊表示數據
參數2:表示當前坐標,即畫出方塊的左上角的坐標x,y
參數3:true表示畫出該方塊,false 表示擦除該方塊。
//方塊在圖形窗口中的位置(即定位4*4大塊的左上角坐標) typedef struct LOCATE
{ int left; int top;
} RockLocation_t;123456
3如何實現同一種類型方塊的翻轉,
在按『↑』時應該翻轉同一種類型的方塊,
比如下面的橫桿和豎桿
@###@###@###@###@@@@############****1234567891011
可以假想成靜態循環鏈表來實現這種方式
使同一種類型的方塊循環起來,
用一個struct結構來表示一種方塊
typedef struct ROCK
{ //用來表示方塊的形狀(每一個位元組是8位,用每4位表示方塊中的一行)
unsigned short rockShapeBits; int nextRockIndex; //下一個方塊,在數組中的下標 } RockType;123456
定義一個RockType類型的數組來存儲19種方塊
RockType RockArray[19] = { (0, 0) };
當我們按「↑」時,把傳入畫方塊函數DrawRock中的rockIndex變為當前方塊結構體中的nextRockIndex即可。
簡單解釋下ReadRock函數的實現:當讀取到空行的時候表示 一種方塊已經讀取完畢,當讀取到****行時 表示同一種類型的方塊讀取完畢,具體看代碼實現,代碼中具體的注釋
4、主要游戲實現的邏輯
貼一個預覽圖吧
註:上述預覽圖的游戲控制區和游戲顯示區在Draw.h的DrawGameWindow()函數實現的
(1)在初始位置畫出方塊,在預覽區畫出下一次的方塊
(2)方塊有兩種行為:響應鍵盤命令UserHitKeyBoard(),自由下落
如果敲擊鍵盤了(w ,a ,s ,d, )空格表示暫停,如果在規定時間內沒有敲擊鍵盤的話,方塊自由下落一個單位
if (kbhit()) //如果敲擊鍵盤了 就處理按鍵
{
userHit = getch();
UserHitKeyBoard(userHit, &curRockIndex, &curRockLocation);
} //沒有 就自動下移一個單位 :不能用else,因為可能按鍵不是上下左右
DWORD newtime = GetTickCount(); if (newtime - oldtime >= (unsigned int)(300) && moveAbled == TRUE)
{
oldtime = newtime;
DisplayRock(curRockIndex, &curRockLocation, false);
curRockLocation.top += ROCK_SQUARE_WIDTH; //下落一格
}1234567891011121314
(3)當方塊落地(即不能下移了)時,判斷是否滿行,如果滿行則消除,然後再判斷游戲是否結束,游戲結束的話,直接退出遊戲
判斷滿行:FullLine()函數,從最底下的一行開始判斷,直到遇到一行空行,
while (count != xROCK_SQUARE_NUM ) //遇到空行 14
{
linefull = true; count = 0; for (int i = 1; i <= xROCK_SQUARE_NUM; ++i)
{ if (game_board[idx][i] == 0)
{
linefull = false; count++;
}
} if (linefull) //滿行,消除當前行,更新分數
{
DelCurLine(idx);//消除滿行
game_socres += 3;
UpdateSocres(game_socres);
idx++;//因為下面要減1
}
idx--;
}
(4)消除滿行
將要刪除的滿行擦除:即將方塊化成與背景色相同的,該代碼為黑色
然後將上面的一行向下移,移一行刪除一行,直到遇到空行
具體看代碼的具體實現 game.h
void DelCurLine(int rowIdx)
(4)判斷方塊是否能移動
在game.h中實現
bool MoveAble(int rockIndex, RockLocation_t* currentLocatePtr, int f_direction)1
**比較當前位置的坐標(左上角)開始,能否放下rockIndex的方塊。
註:f_direction為」↑」的話,則傳入的rockIndex為下一個方塊**
如果不能移動的話,給游戲game_board設置標記表示該位置被佔有
//全局變數-游戲板的狀態描述(即表示當前界面哪些位置有方塊) //0表示沒有,1表示有(多加了兩行和兩列,形成一個圍牆,便於判斷方塊是否能夠移動) int game_board[yROCK_SQUARE_NUM + 2][xROCK_SQUARE_NUM + 2] = { 0 };123
實現過程遇到的一些問題
(1)在快速下落的時候,可能方塊會掉出圍牆的范圍內,
快速下落是使方塊每次下落2個單位距離。
在判斷不能下落時,使當前坐標的top即y減去一個單位的距離
(2)遇到多行滿行時消除不了,
在判斷滿行時,循環找出滿行,找出一個滿行,就消除一行,然後繼續判斷是否滿行,直到遇到空行
㈦ 怎麼用vb製作俄羅斯方塊游戲啊,簡單點的。
visual basic繼承了basic語言易學易用的特點,特別適合於初學者學習windows系統編程。隨著21世紀信息社會的到來,計算機在人們的工作和生活中的深入,要求我們越來越多地與計算機打交道,為了使用戶在繁忙的日程工作中得到放鬆,於是出現了各種各樣的休閑軟體,如聊天工具,游戲等等。於是我們小組著手設計開始一個這樣的游戲軟體。通過這學期來Visual Basic的學習,我初步掌握了Visual Basic語言的最基本的知識,於是在牛榮和李鵬等老師的指導下動手用Visual Basic編寫俄羅斯方塊游戲。
我們之所以選擇開發俄羅斯方塊游戲,無可爭議,《俄羅斯方塊》是有史以來最偉大的游戲之一。 在曾經發布過的所有游戲中,《俄羅斯方塊》還被認為是僅有的一個能夠真正吸引廣泛人群的作品。誰能說清楚,迄今為止人們究竟花了多少萬個小時在這個游戲上?也許這些時間本來可以被花在更具生產力的活動上。某些批評家也許會聲稱,《俄羅斯方塊》要比過去二十年間出現的任何東西都要浪費人們的時間。至於我們,則要欣然提名它為GameSpot評選出的歷史上最偉大游戲之一。
為了懷念經典,也為了能夠給大多的計算機用戶在工作之餘找到一個休閑、娛樂的一個方式,我們小組開始著手用VB語言開發一個經典的俄羅斯方塊游戲。
工程概況
2.1 項目名稱
俄羅斯方塊游戲
2.2 設計平台
VB 全稱Visual Basic,它是以Basic語言作為其基本語言的一種可視化編程工具。
Vb是microsoft公司於1991年退出的windows應用程序開發工具visual意思是「可視化的」。在它剛推出來時,自身還存在一些缺陷,功能也相對少一些。但是經過多年的開發研究。最近microsoft公司又推出了VB6.0版本
VB6.0運行環境:硬體,要求486以上的處理器、16MB以上內存,50MB 以上的硬碟,cd-rom驅動器,滑鼠。軟體:要求windows 95以上版本。
2.3程序設計思想
游戲是用來給大家娛樂的,所以要能在使用的過程中給大家帶來快樂,消除大家的疲勞,所以我們在游戲中添加了漂亮的場景和動聽的音樂,設置了過關升級的功能,激發大家的娛樂激情。
從游戲的基本玩法出發,主要就是俄羅斯方塊的形狀和旋轉,我們在設計中在一個圖片框中構造了一個4*4的網狀小塊,由這些小塊組合成新的形狀,每四個小塊連接在一起就可以構造出一種造型,因此我們總共設計了7中造型,每種造型又可以通過旋轉而變化出2到4種形狀,利用隨機函數在一個欲覽窗體中提前展示形狀供用戶參考,然後將展示的形狀復制到游戲窗體中進行擺放,在游戲窗體中用戶就可以使用鍵盤的方向鍵來控制方塊的運動,然後利用遞歸語句對每一行進行判斷,如果有某行的方塊是滿的,則消除這行的方塊,並且使上面的方塊自由下落,其中,方塊向下的速度是有時鍾控制項控制的,在游戲中,用戶也可以使用向下鍵加快下落速度,定義一個變數,對消除的函數進行記錄,最後就可以得出用戶的分數,用if 語句對分數判斷,達到一定的積分就可以升級到下一個檔次。
俄羅斯方塊游戲設計的主要步驟為以下10個方面:
(1)游戲界面的設計。
(2)俄羅斯方塊的造型。
(3)俄羅斯方塊的旋轉。
(4)俄羅斯方塊的運動情況(包括向左,向右和向下)。
(5)俄羅斯方塊的自動消行功能。
(6)游戲級別的自由選擇。
(7)游戲速度的自由選擇。
(8)游戲得分的計算。
(9)游戲菜單選項的設計及功能實現。
(10)游戲的背景音樂及特效。
2.4運用的控制項和主要對象
我們在設計過程中主要用到的控制項有:command控制項,image控制項,picture控制項,label控制項,timer控制項,text控制項,windows media player控制項等等。
2.5主要實現的功能
我們開發的俄羅斯方塊游戲,主要實現了以下幾種功能:
1.可以靈活控制方塊在圖形框中運動。
2.游戲過程中方塊可以自由旋轉。
3.當某一行的方塊排列滿時,將自動將這一行方塊消除,然後將上面所有方塊向下移動,可以支持連續消行。
4.游戲前可以選擇游戲的速度和游戲的等級,游戲速度既為方塊下落速度,游戲等級為初始游戲時在基層隨機生成一定行數的無規律方塊,生成的行數由你來選擇,每行至少產生5個以上的無規律方塊,這樣增加了游戲難度,對於游戲高手來說,無疑不是一個新的挑戰。
5.游戲的得分支持積分,並且按照公式:
得分 = 原來分數+ 100 * (2 ^ 同時消除的行數-1)
這樣,你同一時間消除的行數越多,你的得分也就越高,當游戲積分到了一定時可以自動升級,這個升級指速度升級。
6.游戲中提供了一個漂亮的場景和動聽的音樂,給你帶來無限激情。
2.6開發人員
由於這次課程設計所選的題目太復雜,而時間又比較緊張,指導老師建議和同學分工完成。我們小組成員包括組長孫磊周,副組長鄒海星,此游戲由我們兩個人共同開發而成。
正文
3.1游戲設計的具體實現
在我們兩個人共同努力下,此次設計,終於能夠圓滿完成。由於時間的緊促,在設計中,也許會有一些考慮不周之處,但其功能已經能夠滿足大多用戶的需求,相信假以時日,一定能做出一個更經典,更完美的俄羅斯方塊游戲,下面我們將對每一步的具體如何實現展示給大家。
3.1.1游戲界面的設計和背景音樂及特效的實現
俄羅斯方塊游戲主要由兩個界面構成,登陸界面和開始游戲界面,在登陸界面中我們可以首先看到聖誕節的晚上飄梅花的場景,梅花從窗體頂部做函數曲線的下落運動,在窗體中定義一個Image控制項組,在通用中定義梅花X坐標變數動態數組,Y坐標變數動態數組,步距X的變數動態數組,步距Y的變數動態數組,以及振幅變數動態數組。然後在窗體form_load中可以定義梅花的數量,利用隨機函數產生隨機的梅花坐標,步距和振幅,Image控制項在運行時候就調用梅花圖片,Image控制項就可以由時鍾控制項控制下落速度,可以自由調節,梅花按snow(i).Left = xp(i) + am(i) * Sin(dx(i))函數在做縱向的正玄函數軌跡運動,豎直方向上為自由下落運動,,有am(i)來控制梅花的左右移動振幅。因此,我們就可以看到一個梅花在空中自由飄舞的畫面了。
背景畫面是用photoshop軟體處理的漂亮圖案,原本畫面中的動畫效果都是由Image控制項製作的,還有點擊進入游戲的按鈕是由Label控制項實現的,因為Image控制項沒有置前置後功能,不能將下雪的場景體現完整性,所以將這些圖案全部放在背景上,不影響雪花飄落的效果,當點擊畫面的時候一樣可以進入游戲界面。
游戲的背景音樂是由一段代碼調用系統播放器Windows Player播放背景音樂,由於本次設計主要是針對游戲如何設計的,所以在這里就不對播放背景音樂的功能做介紹了。
3.1.2俄羅斯方塊的造型
相信朋友們都玩過俄羅斯方塊,對這個游戲的玩法和方塊形狀都比較熟悉。我們這個游戲只選擇了最基本的7中造型,包括長條型,正方型,正S型,反S型,正7型,反7型,T型。如果需要我們可以添加更多的造型。將游戲界面的游戲區圖片框分割成10*20的小塊,每個小塊放置一個command控制項,預覽區圖片框按同樣比例分割成4*4的小塊,同樣有command控制項構成,我們可以把預覽區圖片框看作是從游戲區圖片框中選取的一個部分,游戲區的小方塊編號和欲覽區編號如下圖:
0 1 2 3 4 5 6 7 8 9
… … … … … … … … … …
… … … … … … … … … …
90 91 92 93 94 95 96 97 98 99
3 4 5 6
13 14 15 16
23 24 25 26
33 34 35 36
游戲區編號 欲覽區編號
利用Select將方塊的7中造型列出,比如長條型的設計,在欲覽區中分別有3.4.5.6和5.15.25.35四個方塊構成兩中形態,用數組為:
m(0) = 3: m(1) = 4: m(2) = 5: m(3) = 6: situation2 = 0
m(0) = 5: m(1) = 15: m(2) = 25: m(3) = 35: situation2 = 1
將它的形狀編號為0和1,在後面方便調用,其他的方塊造型同樣的方法。
3.1.3俄羅斯方塊的旋轉
俄羅斯方塊的旋轉主要將方塊的位置加以變換得到的,例如上述範例,長條型有兩中樣式,根據小方塊的編號變動來實現整個造型的旋轉,比如:
If n(0) - 18 >= 2 And n(3) + 9 <= 198 Then
If cmdfang(n(0) - 18).Visible = False And _
cmdfang(n(1) - 9).Visible = False And _
cmdfang(n(3) + 9).Visible = False Then
hidefang 0
n(0) = n(0) - 18
n(1) = n(1) - 9
n(3) = n(3) + 9
showfang 0
situation = 1
End If
End If
方塊的造型在旋轉的時候存在一個公式,當然首先要判斷是否滿足旋轉的要求,以上是一個長條型由橫著變成豎立狀態的旋轉,我們以它的造型中的第三個小方塊n(3)為中心旋轉,這樣,在開始運動的時候,長條形要發生旋轉最少要運動到第三行,才能由橫著變成豎立狀態,游戲區圖形框中第三行的第一個方塊的編號為20,所以長條造型的第一個小方塊的編號n(0)必須要大於20。同樣,長條型方塊在下落到底部的時候也有限制。如果長條下落到最後一行也將無法由橫著變成豎立狀態。
3.1.4如何實現方塊的運動和自動消除滿行的方塊
我們的這個俄羅斯方塊游戲主要是利用command控制項的visible屬性完成效果的,其實在游戲區圖形框可以看成是由許多的command小方塊組成,方塊運動的過程就是造型里方塊顯示或者隱藏,就像現在的霓虹燈效果一樣,由時鍾控制項控制visible屬性改變的速度,上一層的消失,下一層的顯示,這樣,從視覺效果可以看到方塊的下落運動效果。
方塊在下落的過程中會自動判斷每一行方塊的visible屬性,如果全部為true時,就會將這一行小方塊的visible屬性全部變成false,在將上面的小方塊向下移動,利用for語句進行循環判斷,將所有這樣情況的行改變小方塊visible屬性。當有多行同時出現這樣情況時使用遞歸調用,實現連續消行。具體程序代碼如下:
For i = 190 To 10 Step -10
If cmdfang(i).Visible = True And _
cmdfang(i + 1).Visible = True And _
cmdfang(i + 2).Visible = True And _
cmdfang(i + 3).Visible = True And _
cmdfang(i + 4).Visible = True And _
cmdfang(i + 5).Visible = True And _
cmdfang(i + 6).Visible = True And _
cmdfang(i + 7).Visible = True And _
cmdfang(i + 8).Visible = True And _
cmdfang(i + 9).Visible = True Then
For j = i + 4 To i Step -1
t = 1
cmdfang(j).Visible = False
cmdfang(2 * i + 9 - j).Visible = False
For k = 1 To 4000
DoEvents
Next
t = 0
Next
linenum = linenum + 1
For j = i - 1 To 0 Step -1
If cmdfang(j).Visible = True Then
cmdfang(j).Visible = False
cmdfang(j + 10).Visible = True
End If
Next
clearline '為了實現連消數行,這里使用遞歸調用
End If
Next
3.1.5游戲速度和游戲級別自由選擇
游戲速度的自由選擇無非就是改變時鍾控制項的頻率,我們在菜單中添加了選擇速度的功能,還有添加了考驗功能,將欲覽窗中的方塊造型隱藏,給玩家提高了難度,如果你不願意接受考驗也可以點擊顯示還原成原來狀態。
游戲級別的自由選擇是讓用戶選擇游戲開始時候,游戲區底部出現一定行數的隨機方塊,同樣給玩家增加了難度,功能代碼如下:
For i = 19 To 20 - Val(txthard.Text) Step -1
For j = i * 10 To i * 10 + 9
If Rnd >= 0.5 Then cmdfang(j).Visible = True
Next
Next
可以根據你選擇的難度系數在底層的每一行隨機產生超過半數(即5個以上)以上的小方塊,這樣適合喜歡高難度的玩家。
3.1.6游戲得分的計算和游戲菜單的編輯
游戲得分的計算主要是根據消除的行數來決定的,當然每一次同時消除的行數不一樣,每一行的得分也不一樣,如果你每次消除的行數為1,則最後得分是100分,如果同時消除2行,則最後得分是300分,同時消除3行,得分為700分,同時消除4行,得分為1500分,這由公式:得分 = 原來分數+ 100 * (2 ^ 同時消除的行數-1)。
游戲的編輯,讀者可以參照下面的功能介紹。
3.2 游戲功能的介紹
文件-------開始:開始游戲。
繼續:繼續游戲。
暫停:暫時停止游戲,點擊繼續的時候可以繼續游戲。
退出:退出遊戲。
設置-------選擇游戲級別。
選擇游戲速度。
考驗-------顯示:顯示欲覽去方塊。
隱藏:隱藏欲覽去方塊。
幫助-------操作提示以及版本信息和作者資料。
用戶界面具體如圖:
圖—登陸界面 圖—游戲界面
圖—菜單編輯界面 圖—游戲幫助界面
有關說明
經過兩個多星期的設計和開發,俄羅斯方塊游戲已經成功。其功能基本符合用戶需求,能夠完成游戲的控制,方塊的變換以及消層等功能。並提供游戲設置,對於一些技術性比較過硬的玩家,可以調游戲級別、以及游戲速度,使得玩家能夠充分的發揮競技游戲的特色,可以不斷的挑戰自我,挑戰極限。
4.1游戲設計中的不足之處
但是由於課程設計時間較短,所以該游戲還有許多不盡如人意的地方,比如方塊類型太少,退出遊戲不能存儲進度等多方面問題。這些都有待進一步改善,我們在游戲中還可以更換背景音樂,以適合不同的玩家,在每通過一關可以給玩家播放一段flash,吸引玩家去挑戰極限,不斷提高玩家的興趣,相信在以後的製作過程中我們將給大家帶來一個更新功能更全面的游戲。
4.2VB與C語言之間的不同之處
我們這個小游戲也可以用C語言來實現,在程序的編程上沒有VB語言方便實用,C語言和VB語言之間存在很多的共同點,雖然語法方面有點差異,但是在編程思路上完全一樣,VB能夠實現很多C#不能做到的功能,如When語句、Optional參數、局部Static變數、對象實例訪問靜態方法、Handles綁定事件、On Error處理異常、Object直接後期綁定等等。VB和C#語言,編譯出來的是同樣的CIL,但為什麼VB支持很多有趣的特性呢。我們一起來探究一下。
4.21局部靜態變數
VB支持用Static關鍵字聲明局部變數,這樣在過程結束的時候可以保持變數的數值:
Public Sub Test1()
Static i As Integer
i += 1 '實現一個過程調用計數器
End Sub
我們實現了一個簡單的過程計數器。每調用一次Test,計數器的數值就增加1。其實還有很多情況我們希望保持變數的數值。而C#的static是不能用在過程內部的。因此要實現過程計數器,我們必須聲明一個類級別的變數。這樣做明顯不如VB好。因為無法防止其他過程修改計數器變數。這就和對象封裝一個道理,本來應該是一個方法的局部變數,現在我要被迫把它獨立出來,顯然是不好的設計。那麼VB是怎麼生成局部靜態變數的呢?將上述代碼返匯編,我們可以清楚地看到在VB生成的CIL中,i不是作為局部變數,而是作為類的Field出現的: .field private specialname int32 $STATIC$Test1$2001$i
也就是說,i被改名作為一個類的欄位,但被冠以specialname。在代碼中試圖訪問$STATIC$Test1$2001$i是不可能的,因為它不是一個有效的標識符。但是在IL中,將這個變數加一的代碼卻與一般的類欄位完全一樣,是通過ldfld載入的。我覺得這個方法十分聰明,把靜態變數變成生命周期一樣的類欄位,但是又由編譯器來控制訪問的許可權,讓它成為一個局部變數。同時也解釋了VB為什麼要用兩個不同的關鍵字來聲明靜態變數——Static和Shared。由於局部靜態變數的實質是類的欄位,所以它和真正的局部變數還是有所不同的。比如在多線程條件下,對局部靜態變數的訪問就和訪問欄位相同。
4.2.2Handles和WithEvents
VB除了可以用C#那樣的方法來處理事件響應以外,還有從VB5繼承下來的獨特的事件處理方式——WithEvents。
我喜歡稱這種事件處理方式為靜態的事件處理,書寫響應事件的方法時就已經決定該方法響應的是哪一個事件,而C#則是在代碼中綁定事件的。VB中WithEvents靜態方法是非常有用的,它可以顯著增強代碼可讀性,同時也讓VB.net中的事件處理非常方便,不像C#那樣離開了窗體設計器就必須手工綁定事件。
4.2.3類型轉換運算符
在Visual Basic 2005中將加入一個新的運算符——TryCast,相當於C#的as運算符。我一直希望VB有這樣一個運算符。VB目前的類型轉換運算符主要有CType和DirectCast。他們的用法幾乎一樣。我詳細比較了一下這兩個運算符,得出以下結論:
1.在轉換成引用類型時,兩者沒有什麼區別,都是直接調用castclass指令,除非重載了類型轉換運算符CType。DirectCast運算符是不能重載的。
2.轉換成值類型時,CType會調用VB指定的類型轉換函數(如果有的話),比如將String轉換為Int32時,就會自動調用。
4.2.4默認屬性和屬性參數
在原先的VB6里,有一項奇特的功能——默認屬性。在VB6中,對象的名稱可以直接表示該對象的默認屬性。
4.2.5可選參數和按名傳遞
VB從4.0開始支持「可選參數」這一特性。就是說,函數或子程序的參數有些是可選的,調用的時候可以不輸入。其實VB從1.0開始就有一些函數帶有可選參數,只不過到了4.0才讓用戶自己開發這樣的過程。在VB4里,可選參數可以不帶默認值,而在VB里,如果使用可選參數,則必須帶有默認值。在調用的時候,VB若發現參數被省略,則自動讀取.param部分的默認值,並顯式傳遞給過程。這一部分完全由編譯器處理,而且沒有任何性能損失,和手工傳遞所有參數是完全一樣的。至於按名傳遞,VB會自動調整參數的順序,其結果與傳統方式的傳遞也沒有任何的不同。這說明我們可以放心地使用這項便利。而且帶有可選參數的過程拿到C#中,頂多變成不可選參數,也不會造成什麼其他的麻煩。
PS.很多COM組件都使用了默認參數,而且有些過程的參數列表非常長,在VB里可以輕松地處理它們,而在C#中經常讓開發者傳參數傳到吐血。
4.2.6在經過對比之後可得以下一個結論:
1.目前的主流編程語言沒有簡單的,如果你想學精通的話。
2.VB的門檻比較低,編程思想較容易接受。
3.學習C不能短期內見到成效。
4.據用戶調查69%的考生覺得VB更容易接受
致謝
在本次課程設計中,我從指導老師牛榮和李鵬身上學到了很多東西。老師認真負責的工作態度,嚴謹的治學精神和深厚的理論水平都使我收益匪淺。他無論在理論上還是在實踐中,都給與我很大的幫助,使我得到不少的提高這對於我以後的工作和學習都有一種巨大的幫助,感謝他耐心的輔導。
另外,在游戲開發過程中化希耀老師和杜義君老師也給於我們很大的幫助,幫助解決了不少的難點,使得游戲能及時開發完成,還有所有的同學同樣給與我不少幫助,這里一並表示感。
參考文獻:
[1]Vsual Basic 程序設計教程 作者:龔沛曾,陸慰民,楊志強 高等教育出版社出版
[2]Vsual Basic 6.0程序設計 作者:劉新民,蔡瓊,白糠生 清華大學出版社出版
[3]80例上手 VB6 編程 作者:唐凱軍,湯惠莉 山東電子音像出版社
[4]Vsual Basic 實例教程 作者:盧毅 科學出版社出版
[5]Vsual Basic 經典範例50講 作者:趙欣勝,亢慧娟,劉晟宏 科學出版社出版
㈧ 俄羅斯方塊的來源
俄羅斯方塊--可能是這個世界上最出色,最多人玩過,普及率最高的游戲了。但你可知否,在這個游戲的背後,卻有著一段復雜的版權之爭的歷史!
你一定玩過俄羅斯方塊吧!對該游戲,你一定會有自己的觀點和看法,在了解過俄羅斯方塊這款曲折的歷史後,你是否有自己的說話要發表呢?
俄羅斯方塊操作簡單,難度卻不低。作為家喻戶曉老少皆宜的大眾游戲,時至今日玩游戲的人(以及許多不怎麼玩游戲的人)中誰要是不知道的話可真所謂是火星上的熊貓了。但是,誰知道這么優秀的娛樂工具,出自哪位神人之手呢?
顧名思義,俄羅斯方塊自然是俄羅斯人發明的。這位偉人叫做阿列克謝·帕基特諾夫(Alexey Patnov) 。標題畫面中玩GB的大鬍子就是他。看不清楚沒關系,下面來一張近距離接觸的圖片:
其實他還開發了許多優秀的游戲。和許多大牌廠商合作過。這是他的作品年表:
Project Gotham Racing 2 (2003), Microsoft
Fuzion Frenzy (2001), Microsoft
Rampage Puzzle Attack (2001), Midway Games
Tetris Worlds (2001), THQ Inc.
Microsoft Puzzle Collection Entertainment Pack (2000), Swing! Entertainment Media AG
The Next Tetris: Online Edition (2000), Crave Entertainment, Inc.
The Next Tetris (1999), Hasbro Interactive
Pandora's Box (1999), Microsoft
Knight Moves (1996), Spectrum Holobyte, Inc.
Breakthru! (1994), Spectrum Holobyte, Inc.
El-Fish (1993), Maxis Software Inc.
Tetris Pro (1993), 2000 A.D.
Yoshi's Cookie (1993), Nintendo
Super Tetris (1991), Spectrum Holobyte, Inc.
Faces (1990), Spectrum Holobyte, Inc.
Pipe Dream (1990), Bullet-Proof Software, LucasArts
Welltris (1989), Spectrum Holobyte, Inc.
Tetris (1988),
Tetris (original) (1986)
然而,很少有人知道,這個著名的游戲在80年代曾經在法律界掀起軒然大波,那就是著名的俄羅斯方塊產權之爭。這次產權爭奪,幾家歡喜,幾家哀愁,幾家公司倒閉,幾家公司賺錢,其中的是是非非,一言難盡。
1985年6月
工作於莫斯科科學計算機中心的阿列克謝·帕基特諾夫在玩過一個拼圖游戲之後受到啟發,從而製作了一個以Electronica 60(一種計算機)為平台的俄羅斯方塊的游戲。後來經瓦丁·格拉西莫夫(Vadim Gerasimov)移植到PC上,並且在莫斯科的電腦界傳播。帕基特諾夫因此開始小有名氣。
1986年7月
PC版俄羅斯方塊在匈牙利的布達佩斯被當地的一群電腦專家移植到了Apple II 和 Commodore 64 上,這些版本的軟體引起了當時英國一個叫Andromeda的游戲公司經理羅伯特·斯坦恩(Robert Stein)的注意,他向帕基特諾夫以及匈牙利的電腦專家們收購了俄羅斯方塊的版權,並且在買到版權之前把它們倒手賣給了英國的Mirrorsoft (注意不是Microsoft!) 以及美國的Spectrum Holobyte。(什麼人……)
1986年11月
斯坦恩和帕基特諾夫經過談判,就版權收購問題未取得成果。斯坦恩甚至直接飛到莫斯科和帕基特諾夫面談,但是空手而歸。由於俄羅斯人對於已經在西方興起的電子游戲產業知道不多,斯坦恩決定竊取Tetris的版權,於是他放出謠言說這是匈牙利人開發的游戲。
與此同時,PC版的俄羅斯方塊已經由英國的Mirrorsoft出品並且在歐洲銷售,受到當時人們的極大關注。不僅僅因為這個游戲好玩,而且這是「第一個來自鐵幕國家的游戲。」當時的游戲宣傳海報上有濃郁的冷戰色彩,比如戰爭畫面,加加林太空飛行等。而斯坦恩仍然沒有正式合法的版權。
1987年6月
斯坦恩最終取得了在IBM-PC及其兼容機上的Tetris的版權,版權機種包括「其他任何電腦系統」。但是,他沒有和蘇聯方面簽署協議,也就是說,這個版權是不完全的。(譯者註: 這個「其他任何電腦系統」在原文中的描述是"any other computer system",這種說法在當時看來也很不嚴密,從而為後來的產權之爭埋下了伏筆)
1988年1月
Tetris在電腦平台的熱銷,一時造成「洛陽紙貴」(倫敦磁碟貴??)的局面。而當CBS晚報采訪了俄羅斯方塊之父帕基特諾夫之後,斯坦恩盜竊版權的計劃徹底泡湯了。(活該!)一個新的公司ELORG(Electronorgtechinca,蘇聯一家軟體公司)開始和斯坦恩就游戲程序問題進行協商。ELORG的負責人亞歷山大·阿列欣科( Alexander Alexinko)知道斯坦恩雖然沒有版權,但是會以手中的游戲開發程序為籌碼威脅中斷談判。
1988年5月
經過幾個月的爭吵之後,筋疲力盡的斯坦恩終於和ELORG簽定了PC俄羅斯方塊版權的合約。當時的合約禁止開發街機版和掌機版的方塊游戲,而電腦版的Tetris則成為當時最暢銷的游戲。
1988年7月
斯坦恩與阿列欣科商談開發街機版俄羅斯方塊的問題。阿列欣科當時尚未從斯坦恩那裡拿到一分錢的版權費,但是同時的Spectrum 和 Mirrorsoft已經開始向電子游戲商出售了俄羅斯方塊的版權。Spectrum 將Tetris的游戲機和PC在日本的版權賣給了Bullet-Proof Software (FC和GB版俄羅斯方塊的製作商),而Mirrorsoft則把它在日本和北美的版權賣給了美國的Atari。這樣一來兩家公司的矛盾就開始了。 1988年11月,BPS在FC上發行的俄羅斯方塊(大家不很熟悉的俄羅斯方塊1)在日本發售,銷量達200萬份。
1988年11月
隨著GB的開發,NOA(任天堂美國分公司)的經理荒川實(任天堂山內溥老爺子的女婿)希望將Tetris做成GB上的游戲。於是他聯系了BPS的總裁亨克·羅傑斯(Henk Rogers), 羅傑斯再與斯坦恩聯系的時候卻吃了閉門羹。於是他直接去莫斯科購買版權。而斯坦恩覺察出風頭,也乘飛機前往莫斯科;與此同時,Spectrum的負責人羅伯特·麥克斯韋(Robert Maxwell)的兒子凱文·麥克斯韋(Kevin Maxwell) 也在向莫斯科進發。就這樣,三路人馬幾乎在同時趕到了冰天雪地的紅色都市。
1989年2月21日
羅傑斯首先會見了ELORG的代表葉甫蓋尼·別里科夫(Evgeni Belikov,和那個「裝在套子里的人」同名)。他給帕基特諾夫等蘇聯人留下了深刻印象,並且簽了手掌機方塊游戲的版權。之後他向俄國人展示了FC版Tetris,這使別里科夫極為震驚。因為他並沒有授予羅傑斯家用機的版權!羅傑斯則向他們說這是向TENGEN購買的版權,但是別里科夫也從來聽說過TENGEN這個公司的名字。羅傑斯為了緩和尷尬的局面,將斯坦恩隱瞞的事實如數告訴了別里科夫,並且答應付給蘇聯方面更多支票作為已經賣出的FC版俄羅斯方塊的版權費用。這時羅傑斯發現自己有機會買到Tetris全部機種的版權(但是當時還沒買),雖然Atari會對他虎視耽耽,但是別忘了,他和BPS的背後還有任天堂這個大靠山給自己撐腰。
注意:羅伯特·斯坦恩原先所簽的協議只是電腦版Tetris的版權,其他的版權並不是他的。
後來,斯坦恩和ELORG重新簽署了協議。別里科夫強迫他重簽的合約中修改的內容是:「電腦的定義:包含有中央處理器,監視器,磁碟驅動器,鍵盤和操作系統的機器」。而斯坦恩當時卻沒有仔細看這些定義。(這回輪到他犯混了……)後來他才意識到這是羅傑斯從自己手中搶走版權而耍的花招。但是為時已晚。第二天他被告知雖然簽署的文件已經不能改後來,但是他還可以得到街機版Tetris的開發權。三天之後,他簽下了街機版的協議。
1989年2月22日
凱文·麥克斯韋訪問了ELORG。別里科夫拿出羅傑斯給他的FC游戲卡向他詢問這件事情。麥克斯韋在卡帶上看到了Mirrorsoft的名字後才想起他的公司已經把部分版權倒賣給了Atari。(糊塗人辦糊塗事……)當他想繼續談街急和手掌機版權的問題的時候,卻發現自己他能夠簽的,就只有除電腦,街機,家用機和掌機以外的協議了。(其實等於沒有協議可簽,除非他發明一種新的娛樂系統,比方說俄羅斯方塊積木……)在糊塗之餘這傢伙靈機一動,告訴別里科夫說此卡帶為盜版(汗……),然後也要簽家用機的協議。
最後的結果是:凱文·麥克斯韋只帶走一張白紙,羅伯特·斯坦恩帶走了街機協議書。由於麥克斯韋聲稱所有的FC卡都是盜版,ELORG保留了家用機的版權,沒賣給任何人。假如麥克斯韋想獲得家用機版權的話,就必須出價比任天堂高才行。亨克·羅傑斯買到了掌機的版權,並且通知了荒川實。BPS就製作GB版Tetris向任天堂達成交易:這筆交易額高大500萬-1000萬美元。
1989年3月15日
亨克&#8226;羅傑斯回到莫斯科,並且代表任天堂出巨資收購家用機版Tetris的版權。版權費的價格雖然沒有向外界透露,但是這個數字將是Mirrorsoft永遠拿不出來的。連荒川實和NOA的首席執行官霍華德·林肯(Howard Lincoln)都親自前往蘇聯助陣。
1989年3月22日
ELORG和任天堂的家用機協議終於達成。任天堂方面堅持加入一款聲明,在協議簽定之後,如果和其他出現法律糾紛,蘇聯方面必須派人去美國的法庭上做證。實際上,這種法律上的爭端將是不可避免的。據說ELORG僅僅得到的定金有300-500萬美元之多。別里科夫向Mirrorsoft通知,說Mirrorsoft, Andromeda和Tengen都沒有家用機的版權,現在版權都歸任天堂所有。當天晚上任天堂和BPS的頭目們在莫斯科酒店裡舉行了慶祝party。
(各位看明白了,現在家用機和掌機的版權已經被任天堂和BPS分別掌握在手中。無論是Atari還是Tengen都沒有權利製作FC版的俄羅斯方塊。)
1989年3月31日
霍華德·林肯 愉快(幸災樂禍?)地向Atari發去最後通牒(傳真),告訴他們立刻停止FC(NES)版的俄羅斯方塊游戲。這使得Atari和麥克斯韋都十分震怒。他們以Tengen的名義回信說在4月7日那天他們就已經享有家用機俄羅斯方塊的版權了。
1989年4月13日
Tengen撰寫了一份申請書,要求擁有Tetris的「影音作品,源程序和游戲音樂」版權。但是申請書中並沒有提及阿列克謝·帕基特諾夫和任天堂的游戲版權問題。(忽視了阿列克謝·帕基特諾夫真是個大錯誤!)
與此同時,麥克斯韋利用自己掌握的媒體勢力,企圖奪回Tetris的陣地。甚至搬出了蘇聯與英國政府,對俄羅斯方塊版權問題進行干預。(好大的面子啊!)結果挑起了蘇共(!)與ELORG之間的矛盾。甚至連戈爾巴喬夫都向麥克斯韋保證「以後不用擔心日本公司的問題」。(汗……這位麥克斯韋果然不是善主……偉大的蘇聯政府都對俄羅斯方塊關注起來了……)
在4月晚些時候,霍華德·林肯回到莫斯科的時候,發現ELORG已經在蘇聯政府的打壓下抬不起頭來,而就在那天半夜,NOA方面給他打電話,說Tengen已經起訴了任天堂。(山雨欲來風滿樓啊……)
第二天,他面會了別里科夫,帕基特諾夫和其他幾位ELORG的成員,以確保他們能夠為任天堂的官司佐證。(這回合同里的條款可生效了)隨後NOA立刻反訴Tengen,並且開始收集證據。
1989年5月17日
Tengen在USA Today上登載了大幅Tertis廣告,雖然法庭大戰已經迫在眉睫。
1989年6月
Tengen與任天堂的案子終於開庭審理。
論戰主要圍繞一個議題展開:NES(FC)究竟是電腦,還是電子游戲機。(大家不許笑,在法庭上這可是很嚴肅的話題)Atari認為NES是電腦系統,因為它擁有擴展機能,而且日本的Famicom也有網路功能存在。而任天堂的證據則更加切題:ELORG中的蘇聯人從來沒有意向出售Tetris的家用機版權,而所謂的「電腦」的概念則早在和斯坦恩的協議中提到了。
1989年6月15日
法庭召開聽證會,討論關於任天堂和Tengen互相命令對方終止生產和銷售各自的Tetris軟體的行為。法官福恩·史密斯(Fern Smith)宣布Mirrorsoft 與 Spectrum Holobyte均沒有家用機版權,因此他們提供給Tengen的權利也不能生效。任天堂的請求最後得到了許可。
1989年6月21日
Tengen版的俄羅斯方塊全部撤下了貨架,該游戲卡帶的生產也被迫中止。數十萬份軟體留在包裝盒裡,封存在倉庫中。
1989年7月
任天堂NES版Tetris在美國發售。全美銷量大約300萬。與此同時,和GB版Tetris捆綁銷售的Game Boy席捲美國,美利堅大地上颳起一陣方塊旋風。
關於Tetris的混戰此時已經告一段落。而任天堂和Tengen之間的法庭糾紛則一直持續到1993年。
尾聲
Atari Games仍然開發了街機版的Tetris,共賣出約2萬台機器。近來Atari Games 被 Williams/WMS收購,而那些封存在倉庫里的NES版Tetris的命運則沒人知道。Tengen不能從其他途徑把它們處理掉,所以估計這些軟體都被銷毀了。但是據說仍然有約10萬份Tengen版的Tetris流入了市場。
我們今天在64合一等游戲D版卡里玩到的所謂「俄羅斯方塊2」其實就是當年的Tengen版,平心而論,這一版的方塊比BPS的版本要好玩許多。首先,這版的操作感和按鍵設定十分到位,AB分別是正轉和反轉,而BPS版是用十字鍵的下來轉動,只支持一個方向,按A就直接「啪」地落下來,手感十分不爽;其次,它支持的二人對戰,與電腦競爭和合作的模式也讓人耳目一新。還有,音樂也是沒的說。
羅伯特·斯坦恩,這個版權問題的始作俑者,在Tetris上總共只賺了25萬美元。本來他可以掙多點錢的,但是Atari和Mirrorsoft在付他版稅的時候沒有給足。(應得的報應……)
Spectrum Holobyte 則需要和ELORG重新協商,以確保電腦版Tetris的版權。
羅伯特·麥克斯韋的媒體堡壘在混戰中逐漸分崩離析,老麥克斯韋在做生意時做幕後黑手的事實也在調查中,而他卻突然暴病身亡。(氣死的……)Mirrorsoft 英國公司也慘淡地退出了歷史舞台。
真正的大贏家是BPS的總裁亨克·羅傑斯,還有幕後的任天堂。俄羅斯方塊究竟為任天堂賺了多少銀子呢?答案恐怕永遠說不清了。想一想吧,在美國GB都是和Tetris捆綁銷售,以增加GB的出貨量……然後因為Tetris買了GB的人還會買其他的GB卡……要是這么算起來的話,那利潤簡直就像滾雪球一樣了。現在GB版的Tetris(Z版)總共生產了3000萬張。(後來GB的俄羅斯方塊又在SFC上出了復刻版,和《馬里奧醫生》一起出現在屏幕上,成為不朽之作。)
至於蘇聯方面,除了蘇聯政府,誰也沒有從Tetris那裡得到多少好處。蘇聯解體之後,原ELORG的人員都四散到了全國乃至世界各地,許多人繼續開發游戲(比方說帕基特諾夫)。
阿列克謝·帕基特諾夫幾乎沒有從Tetris上賺到一分錢。ELORG本來打算給他Tetris的銷售權,但是旋即取消了這筆交易。不過帕基特諾夫仍然為自己能夠製作出這么一個世界聞名的優秀游戲而欣慰。他從科學院里得到一台286(當時在蘇聯可是了不起的電腦)作為獎勵。而且分到了比同事們家寬敞明亮的房子。在1996年,亨克·羅傑斯支付給他一筆報酬(還算是個知恩圖報的人),帕基特諾夫組建了Tetris Company LLC 公司,終於能夠自己創作游戲,並且收取版權費了。
譯者註:當年俄羅斯方塊紅遍世界的各個角落,一個本來是吃大鍋飯的人在消極怠工的時候發明的娛樂工具成了造福全人類的寶貝,它的價值遠遠超越了開發這個軟體時候的預想。Atari雖然在法庭上慘敗,但是拜亞洲盜版商人所賜,Tengen版的俄羅斯方塊已經在中國玩家心目中生根發芽,長葉開花,任天堂的正統Tetris在中國反而沒人玩了。其實說了那麼多,歸根到底,平平淡淡才是真。有機會的話,下載一個FC的模擬器和一個64合一的經典ROM,回家體會一下俄羅斯方塊的魅力吧……
㈨ 用c語言編寫俄羅斯方塊程序 求詳解
1、用C語言繪制圖形界面
EasyX圖形庫(http://www.easyx.cn)即TC的圖形庫在VC下的移植。
包含庫#include <graphics.h>
先初始化圖形窗口
initgraph(WINDOW_WIDTH, WINDOW_HIGH) ;WINDOW_WIDTH為窗口的寬頻,WINDOW_HIGH為窗口的高度。
清空繪圖設備
cleardevice();
設置畫筆顏色
setcolor(RED) ;
設置線條風格
setlinestyle(PS_SOLID, NULL, 0);
畫矩形
rectangle
還有畫線、顯示文字等函數,可以參照其幫助文檔。
注意:由於我們用的是EasyX圖形庫,故源文件後綴要為.cpp,但其中內容都是C的語法。
2、存儲表示出俄羅斯方塊的形狀
一、我們可以用編號,不同的編號代表不同的俄羅斯方塊,根據編號把不同方塊的畫法寫在代碼中,這樣19種
方塊就得有19種相應的代碼來描繪。而且這樣擴展性不好,若以後設計了新的方塊,則需要更改大量源代碼。
二、我們很自然的想到可用字模點陣的形式來表示,即設置一個4行4列的數組,元素置1即代表這個位置有小
方塊,元素置0即代表這個位置無小方塊,這個整個的4*4的數組組成俄羅斯方塊的形狀。
1000
1000
1100
0000
我們把俄羅斯方塊點陣的數位存在rockArray中,我們可以事先把這19種方塊的字模點陣自己轉化成十六進制,然後在rockArray數組的初始化時賦值進去。
但這樣做未免有點太費力,且擴展性也不太好,若以後設計的新方塊種類加入,要改變數組rockArray中的值。
我們可以考慮把所有俄羅斯方塊的點陣存儲在配置文件中,在程序初始化時讀取文件,把這些點陣轉換成unsigned int的變數存儲在rockArray中。
這樣,以後我們增添新的方塊形狀只需要在配置文件中增加新的點陣即可。
@###
@###
@@##
####(為使得看起來更醒目,我們用@表示1,用#表示0)
3、讓圖形動起來
在某位置處用函數DrawRock在屏幕上畫出俄羅斯方塊,然後再擦除掉(即用背景色在原位置處重繪一次方塊),最後在下落的下一個位置處用函數DrawRock在屏幕上畫出俄羅斯方塊,如此循環,中間用計時器間隔一段時間以控制下落的速度。
同理,按下屏幕的左右鍵也是如此,只是在按下鍵盤時把方塊的位置重新計算了。
那麼按下上方向鍵時,如何讓方塊翻轉呢?
我們在配置文件中就把方塊的順時針翻轉形態放在了一起:
@###
@###
@@##
####
@@@#
@###
####
####
@@##
#@##
#@##
####
##@#
@@@#
####
####
我們每按一次上方向鍵改變一次方塊的形狀即可。若一直按上鍵,形狀應該是循環地翻滾。
我們想到了循環鏈表的數據結構可實現這個效果。
可是我們若把這些一種類的方塊的各種形態串成循環鏈表形式,那麼每次重新生成方塊時我們就難以隨機地生成方塊了。
故還是得用數組來存儲,但又要有循環鏈表的功能,於是我們想到了靜態循環鏈表。
我們用結構體來作為一個方塊在rockArray中的元素
typedef struct ROCK
{ //用來表示方塊的形狀(每一個位元組是8位,用每4位表示方塊中的一行)
unsigned int rockShapeBits ;
int nextRockIndex ; //下一個方塊,在數組中的下標
} RockType ;
這樣,當我們按下上方向鍵時,把傳入函數DrawRock中的rockIndex變為當前方塊結構體中的nextRockIndex即可。
㈩ 改寫俄羅斯方塊 C語言
我還是覺得E語言比較好用,國產的。
易語言是一個自主開發,適合國情,不同層次不同專業的人員易學易用的漢語編程語言。易語言降低了廣大電腦用戶編程的門檻,尤其是根本不懂英文或者英文了解很少的用戶,可以通過使用本語言極其快速地進入Windows程序編寫的大門。易語言漢語編程環境是一個支持基於漢語字、詞編程的、全可視化的、跨主流操作系統平台的編程工具環境;擁有簡、繁漢語以及英語、日語等多語種版本;能與常用的編程語言互相調用;具有充分利用API,COM、DLL、OCX組件,各種主流資料庫,各種實用程序等多種資源的介面和支撐工具。易語言有自主開發的高質量編譯器,中文源代碼被直接編譯為CPU指令,運行效率高,安全可信性高;擁有自己的資料庫系統,且支持訪問現有所有資料庫;內置專用輸入法,支持中文語句快速錄入,完全解決了中文輸入慢的問題;易語言除了支持界面設計的可視化,還支持程序流程的即時可視化;除了語句的中文化之外,易語言中還專門提供了適合中國國情的命令,如中文格式日期和時間處理、漢字發音處理、全半形字元處理、人民幣金額的處理等;易語言綜合採用了結構化、面向對象、組件、構架、集成化等多種先進技術,並在運行效率、性能價格比、全可視化支持、適應本地化需要、面向對象以及提供Windows,Linux上的運行平台等具有特色;現有各種支持庫多達40多個,用戶可以使用她來滿足幾乎所有的Windows編程需求,多媒體功能支持強大,完善的網路、埠通訊和互聯網功能支持,網上與論壇上的學習資源眾多。在易語言及其編譯器的設計與實現、可視化漢語編程的構建、提供多種語言版本等方面具有創新。目前易語言已取得國家級鑒定,鑒定會專家一致認為:易語言在技術上居於國內領先地位,達到了當前同類產品的國際先進水平。
參考資料:http://www.dywt.com.cn/