Desc:俄罗斯方块游戏
By:hoodlum1980
Email:jinfd@126.com
Date:2008.03.12 22:30
********************************/
#include <stdio.h>
#include <bios.h>
#include <dos.h>
#include <graphics.h>
#include <string.h>
#include <stdlib.h>
#define true 1
#define false 0
#define BoardWidth 12
#define BoardHeight23
#define _INNER_HELPER /* inner helper method */
/*Scan Codes Define*/
enum KEYCODES
{
K_ESC=0x011b,
K_UP =0x4800,/* upward arrow */
K_LEFT =0x4b00,
K_DOWN =0x5000,
K_RIGHT =0x4d00,
K_SPACE =0x3920,
K_P =0x1970
}
/* the data structure of the block */
typedef struct tagBlock
{
char c[4][4] /* cell fill info array, 0-empty, 1-filled */
int x /* block position cx [ 0,BoardWidht -1] */
int y /* block position cy [-4,BoardHeight-1] */
char color /* block color */
char size /* block max size in width or height */
char name /* block name (the block's shape) */
} Block
/* game's global info */
int FrameTime= 1300
int CellSize= 18
int BoardLeft= 30
int BoardTop=30
/* next block grid */
int NBBoardLeft= 300
int NBBoardTop=30
int NBCellSize= 10
/* score board position */
int ScoreBoardLeft= 300
int ScoreBoardTop=100
int ScoreBoardWidth=200
int ScoreBoardHeight=35
int ScoreColor=LIGHTCYAN
/* infor text postion */
int InfoLeft=300
int InfoTop=200
int InfoColor=YELLOW
int BorderColor=DARKGRAY
int BkGndColor=BLACK
int GameRunning=true
int TopLine=BoardHeight-1 /* top empty line */
int TotalScore=100
char info_score[20]
char info_help[255]
char info_common[255]
/* our board, Board[x][y][0]-isFilled, Board[x][y][1]-fillColor */
unsigned char Board[BoardWidth][BoardHeight][2]
char BufferCells[4][4] /* used to judge if can rotate block */
Block curBlock /* current moving block */
Block nextBlock /* next Block to appear */
/* function list */
int GetKeyCode()
int CanMove(int dx,int dy)
int CanRotate()
int RotateBlock(Block *block)
int MoveBlock(Block *block,int dx,int dy)
void DrawBlock(Block *block,int,int,int)
void EraseBlock(Block *block,int,int,int)
void DisplayScore()
void DisplayInfo(char* text)
void GenerateBlock(Block *block)
void NextBlock()
void InitGame()
int PauseGame()
void QuitGame()
/*Get Key Code */
int GetKeyCode()
{
int key=0
if(bioskey(1))
{
key=bioskey(0)
}
return key
}
/* display text! */
void DisplayInfo(char *text)
{
setcolor(BkGndColor)
outtextxy(InfoLeft,InfoTop,info_common)
strcpy(info_common,text)
setcolor(InfoColor)
outtextxy(InfoLeft,InfoTop,info_common)
}
/* create a new block by key number,
* the block anchor to the top-left corner of 4*4 cells
*/
void _INNER_HELPER GenerateBlock(Block *block)
{
int key=(random(13)*random(17)+random(1000)+random(3000))%7
block->size=3/* because most blocks' size=3 */
memset(block->c,0,16)
switch(key)
{
case 0:
block->name='T'
block->color=RED
block->c[1][0]=1
block->c[1][1]=1, block->c[2][1]=1
block->c[1][2]=1
break
case 1:
block->name='L'
block->color=YELLOW
block->c[1][0]=1
block->c[1][1]=1
block->c[1][2]=1, block->c[2][2]=1
break
case 2:
block->name='J'
block->color=LIGHTGRAY
block->c[1][0]=1
block->c[1][1]=1
block->c[1][2]=1, block->c[0][2]=1
break
case 3:
block->name='z'
block->color=CYAN
block->c[0][0]=1, block->c[1][0]=1
block->c[1][1]=1, block->c[2][1]=1
break
case 4:
block->name='5'
block->color=LIGHTBLUE
block->c[1][0]=1, block->c[2][0]=1
block->c[0][1]=1, block->c[1][1]=1
break
case 5:
block->name='o'
block->color=BLUE
block->size=2
block->c[0][0]=1, block->c[1][0]=1
block->c[0][1]=1, block->c[1][1]=1
break
case 6:
block->name='I'
block->color=GREEN
block->size=4
block->c[1][0]=1
block->c[1][1]=1
block->c[1][2]=1
block->c[1][3]=1
break
}
}
/* get next block! */
void NextBlock()
{
/* copy the nextBlock to curBlock */
curBlock.size=nextBlock.size
curBlock.color=nextBlock.color
curBlock.x=(BoardWidth-4)/2
curBlock.y=-curBlock.size
memcpy(curBlock.c,nextBlock.c,16)
/* generate nextBlock and show it */
EraseBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize)
GenerateBlock(&nextBlock)
nextBlock.x=1,nextBlock.y=0
DrawBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize)
}
/* rotate the block, update the block struct data */
int _INNER_HELPER RotateCells(char c[4][4],char blockSize)
{
char temp,i,j
switch(blockSize)
{
case 3:
temp=c[0][0]
c[0][0]=c[2][0], c[2][0]=c[2][2],c[2][2]=c[0][2], c[0][2]=temp
temp=c[0][1]
c[0][1]=c[1][0], c[1][0]=c[2][1],c[2][1]=c[1][2], c[1][2]=temp
break
case 4:/* only 'I' block arived here! */
c[1][0]=1-c[1][0], c[1][2]=1-c[1][2], c[1][3]=1-c[1][3]
c[0][1]=1-c[0][1], c[2][1]=1-c[2][1],c[3][1]=1-c[3][1]
break
}
}
/* judge if the block can move toward the direction */
int CanMove(int dx,int dy)
{
int i,j,tempX,tempY
for(i=0i<curBlock.sizei++)
{
for(j=0j<curBlock.sizej++)
{
if(curBlock.c[i][j])
{
/* cannot move leftward or rightward */
tempX = curBlock.x + i + dx
if(tempX<0 || tempX>(BoardWidth-1))return false/* make sure x is valid! */
/* cannot move downward */
tempY = curBlock.y + j + dy
if(tempY>(BoardHeight-1))return false/* y is only checked lower bound, maybe negative!!!! */
/* the cell already filled, we must check Y's upper bound before check cell ! */
if(tempY>=0 &&Board[tempX][tempY][0]) return false
}
}
}
return true
}
/* judge if the block can rotate */
int CanRotate()
{
int i,j,tempX,tempY
/* update buffer */
memcpy(BufferCells, curBlock.c, 16)
RotateCells(BufferCells,curBlock.size)
for(i=0i<curBlock.sizei++)
{
for(j=0j<curBlock.sizej++)
{
if(BufferCells[i][j])
{
tempX=curBlock.x+i
tempY=curBlock.y+j
if(tempX<0 || tempX>(BoardWidth-1))
return false
if(tempY>(BoardHeight-1))
return false
if(tempY>=0 &&Board[tempX][tempY][0])
return false
}
}
}
return true
}
/* draw the block */
void _INNER_HELPER DrawBlock(Block *block,int bdLeft,int bdTop,int cellSize)
{
int i,j
setfillstyle(SOLID_FILL,block->color)
for(i=0i<block->sizei++)
{
for(j=0j<block->sizej++)
{
if(block->c[i][j] &&(block->y+j)>=0)
{
floodfill(
bdLeft+cellSize*(i+block->x)+cellSize/2,
bdTop+cellSize*(j+block->y)+cellSize/2,
BorderColor)
}
}
}
}
/* Rotate the block, if success, return true */
int RotateBlock(Block *block)
{
char temp,i,j
int b_success
if(curBlock.size==2)
return
if(( b_success=CanRotate()))
{
EraseBlock(block,BoardLeft,BoardTop,CellSize)
memcpy(curBlock.c,BufferCells,16)
DrawBlock(block,BoardLeft,BoardTop,CellSize)
}
return b_success
}
/* erase a block, only fill the filled cell with background color */
void _INNER_HELPER EraseBlock(Block *block,int bdLeft,int bdTop,int cellSize)
{
int i,j
setfillstyle(SOLID_FILL,BkGndColor)
for(i=0i<block->sizei++)
{
for(j=0j<block->sizej++)
{
if(block->c[i][j] &&(block->y+j>=0))
{
floodfill(
bdLeft+cellSize*(i+block->x)+cellSize/2,
bdTop+cellSize*(j+block->y)+cellSize/2,
BorderColor)
}
}
}
}
/* move by the direction if can, donothing if cannot
* return value: true - success, false - cannot move toward this direction
*/
int MoveBlock(Block *block,int dx,int dy)
{
int b_canmove=CanMove(dx,dy)
if(b_canmove)
{
EraseBlock(block,BoardLeft,BoardTop,CellSize)
curBlock.x+=dx
curBlock.y+=dy
DrawBlock(block,BoardLeft,BoardTop,CellSize)
}
return b_canmove
}
/* drop the block to the bottom! */
int DropBlock(Block *block)
{
EraseBlock(block,BoardLeft,BoardTop,CellSize)
while(CanMove(0,1))
{
curBlock.y++
}
DrawBlock(block,BoardLeft,BoardTop,CellSize)
return 0/* return value is assign to the block's alive */
}
/* init the graphics mode, draw the board grid */
void InitGame()
{
int i,j,gdriver=DETECT,gmode
struct time sysTime
/* draw board cells */
memset(Board,0,BoardWidth*BoardHeight*2)
memset(nextBlock.c,0,16)
strcpy(info_help,"P: Pause Game. --by hoodlum1980")
initgraph(&gdriver,&gmode,"c:\\tc\\")
setcolor(BorderColor)
for(i=0i<=BoardWidthi++)
{
line(BoardLeft+i*CellSize, BoardTop, BoardLeft+i*CellSize, BoardTop+ BoardHeight*CellSize)
}
for(i=0i<=BoardHeighti++)
{
line(BoardLeft, BoardTop+i*CellSize, BoardLeft+BoardWidth*CellSize, BoardTop+ i*CellSize)
}
/* draw board outer border rect */
rectangle(BoardLeft-CellSize/4, BoardTop-CellSize/4,
BoardLeft+BoardWidth*CellSize+CellSize/4,
BoardTop+BoardHeight*CellSize+CellSize/4)
/* draw next block grids */
for(i=0i<=4i++)
{
line(NBBoardLeft+i*NBCellSize, NBBoardTop, NBBoardLeft+i*NBCellSize, NBBoardTop+4*NBCellSize)
line(NBBoardLeft, NBBoardTop+i*NBCellSize, NBBoardLeft+4*NBCellSize, NBBoardTop+ i*NBCellSize)
}
/* draw score rect */
rectangle(ScoreBoardLeft,ScoreBoardTop,ScoreBoardLeft+ScoreBoardWidth,ScoreBoardTop+ScoreBoardHeight)
DisplayScore()
/* set new seed! */
gettime(&sysTime)
srand(sysTime.ti_hour*3600+sysTime.ti_min*60+sysTime.ti_sec)
GenerateBlock(&nextBlock)
NextBlock() /* create first block */
setcolor(DARKGRAY)
outtextxy(InfoLeft,InfoTop+20,"Up -rotate Space-drop")
outtextxy(InfoLeft,InfoTop+35,"Left-leftRight-right")
outtextxy(InfoLeft,InfoTop+50,"Esc -exit")
DisplayInfo(info_help)
}
/* set the isFilled and fillcolor data to the board */
void _INNER_HELPER FillBoardData()
{
int i,j
for(i=0i<curBlock.sizei++)
{
for(j=0j<curBlock.sizej++)
{
if(curBlock.c[i][j] &&(curBlock.y+j)>=0)
{
Board[curBlock.x+i][curBlock.y+j][0]=1
Board[curBlock.x+i][curBlock.y+j][1]=curBlock.color
}
}
}
}
/* draw one line of the board */
void _INNER_HELPER PaintBoard()
{
int i,j,fillcolor
for(j=max((TopLine-4),0)j<BoardHeightj++)
{
for(i=0i<BoardWidthi++)
{
fillcolor=Board[i][j][0]? Board[i][j][1]:BkGndColor
setfillstyle(SOLID_FILL,fillcolor)
floodfill(BoardLeft+i*CellSize+CellSize/2,BoardTop+j*CellSize+CellSize/2,BorderColor)
}
}
}
/* check if one line if filled full and increase the totalScore! */
void _INNER_HELPER CheckBoard()
{
int i,j,k,score=10,sum=0,topy,lines=0
/* we find the top empty line! */
j=topy=BoardHeight-1
do
{
sum=0
for(i=0i<BoardWidthi++)
{
sum+=Board[i][topy][0]
}
topy--
} while(sum>0 &&topy>0)
/* remove the full filled line (max remove lines count = 4) */
do
{
sum=0
for(i=0i<BoardWidthi++)
sum+=Board[i][j][0]
if(sum==BoardWidth)/* we find this line is full filled, remove it! */
{
/* move the cells data down one line */
for(k=jk >topyk--)
{
for(i=0i<BoardWidthi++)
{
Board[i][k][0]=Board[i][k-1][0]
Board[i][k][1]=Board[i][k-1][1]
}
}
/* make the top line empty! */
for(i=0i<BoardWidthi++)
{
Board[i][topy][0]=0
Board[i][topy][1]=0
}
topy++ /* move the topline downward one line! */
lines++ /* lines <=4 */
TotalScore+=score
score*=2 /* adding: 10, 30, 70, 150 */
}
else
j--
} while(sum>0 &&j>topy &&lines<4)
/* speed up the game when score is high, minimum is 400 */
FrameTime=max(1200-100*(TotalScore/200), 400)
TopLine=topy/* update the top line */
/* if no lines remove, only add 1: */
if(lines==0)
TotalScore++
}
/* display the score */
void _INNER_HELPER DisplayScore()
{
setcolor(BkGndColor)
outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score)
setcolor(ScoreColor)
sprintf(info_score,"Score: %d",TotalScore)
outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score)
}
/* we call this function when a block is inactive. */
void UpdateBoard()
{
FillBoardData()
CheckBoard()
PaintBoard()
DisplayScore()
}
/* pause the game, and timer handler stop move down the block! */
int PauseGame()
{
int key=0
DisplayInfo("Press P to Start or Resume!")
while(key!=K_P &&key!=K_ESC)
{
while(!(key=GetKeyCode())){}
}
DisplayInfo(info_help)
return key
}
/* quit the game and do cleaning work. */
void QuitGame()
{
closegraph()
}
/* the entry point function. */
void main()
{
int i,flag=1,j,key=0,tick=0
InitGame()
if(PauseGame()==K_ESC)
goto GameOver
/* wait until a key pressed */
while(key!=K_ESC)
{
/* wait until a key pressed */
while(!(key=GetKeyCode()))
{
tick++
if(tick>=FrameTime)
{
/* our block has dead! (can't move down), we get next block */
if(!MoveBlock(&curBlock,0,1))
{
UpdateBoard()
NextBlock()
if(!CanMove(0,1))
goto GameOver
}
tick=0
}
delay(100)
}
switch(key)
{
case K_LEFT:
MoveBlock(&curBlock,-1,0)
break
case K_RIGHT:
MoveBlock(&curBlock,1,0)
break
case K_DOWN:
MoveBlock(&curBlock,0,1)
break
case K_UP:
RotateBlock(&curBlock)
break
case K_SPACE:
DropBlock(&curBlock)
break
case K_P:
PauseGame()
break
}
}
GameOver:
DisplayInfo("GAME OVER! Press any key to exit!")
getch()/* wait the user Press any key. */
QuitGame()
}
俄罗斯方块的C语言实现,在WIN-TC上编译通过。
微信小程序的左右滑动触屏事件,主要有三个事件:touchstart,touchmove,touchend。这三个事件最重要的属性是pageX和pageY,表示X,Y坐标。
touchstart在触摸开始时触发事件
touchend在触摸结束时触发事件
touchmove触摸的过程中不断激发这个事件
这三个事件都有一个timeStamp的属性,查看timeStamp属性,可以看到顺序是touchstart =>touchmove=>touchmove =>··· =>touchmove =>touchend。
<view>父组件msg的值:{{msg}}</view>
<Header msg="{{msg}}" bindchildChange="change" ></Header>
<block wx:for="{{list}}" wx:key="index">
<ListItem rItem="{{item}}" bindchildGO="childGO"></ListItem>
</block>
<Header msg="{{msg}}"></Header>
/* pages/list/list.wxss */
.item{
padding: 5px
}
img1{
width: 120px
height: 120px
border-radius: 5px
}
.row{
flex: 1
height: 120px
}
.title{
padding: 10px
}
.dec{
padding:0 10px
}
// pages/list/list.js
Page({
/**
* 页面的初始数据
*/
data: {
msg:"你是我的小宝贝",
list:[{
url:"https://www.baidu.com",
imageUrl:"https://img1.baidu.com/it/u=2519912129,4264910682&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500",
title:"我的小可爱",
content:"可爱可爱"
},
{
imageUrl:"https://img1.baidu.com/it/u=931545919,4030748642&fm=253&fmt=auto&app=138&f=JPEG?w=306&h=459",
title:"我的小可爱",
content:"mao可爱可爱"
},]
},
change:function(str){
this.setData({
msg:str.detail
})
},
childGO(e){
wx.navigateTo({
url: '/pages/webpage/webpage?url='+e.detail,
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
"usingComponents": {
"ListItem":"/components/ListItem/ListItem",
"Header":"/components/Header/Header"
}
<view class="flex item" bindtap="go" data-url="{{rItem.url}}">
<image class="img1" src="{{rItem.imageUrl}}"></image>
<view class="row">
<view class="title">{{rItem.title}}</view>
<view class="dec">{{rItem.content}}</view>
</view>
</view>
.img1{
width: 120px
height: 120px
display: block
border-radius: 5px
}
.item{
padding: 5px
}
.row{
flex: 1
height: 120px
}
.title{
padding: 10px
}
.dec{
padding: 0 10px
}
.flex{
display: flex
}
.flex-between{
justify-content: space-between
}
.flex-center{
justify-content: center
align-items: center
}
// components/ListItem/ListItem.js
Component({
/**
* 组件的属性列表
*/
properties: {
/* 子组件用properties来接收对象 */
rItem:{
/* 如果没有传入对象显示的默认值 */
type:Object,
value:{
imageUrl:'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.zhimg.com%2Fv2-a7c5da54b8008049fe43089752c74ce2_r.jpg%3Fsource%3D1940ef5c&refer=http%3A%2F%2Fpic1.zhimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648446806&t=9f16e5a2c12d51ba32169795e4d339f7',
title:'我的小可爱',
content:'我的小可爱我的小可爱我的小可爱我的小可爱'}
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
go(e){
console.log(e)
let url = e.currentTarget.dataset.url
this.triggerEvent('childGO',url)
}
}
})
<view class="t" bindtap="handler" >{{msg}}</view>
.t{
font-size: 25px
padding: 10px
text-align: center
}
// components/Header/Header.js
Component({
/**
* 组件的属性列表
*/
properties: {
msg:{
type:String,
value:'我是Header'
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
handler:function(){
/* 直接改子组件里的msg父组件不会同步所以不能直接改 */
/* this.setData({
msg:'你好'
}) */
this.triggerEvent('childChange','你可真坏啊')
},
}
})
<button bindtap="getuserInfo" plain type="primary">获取用户信息</button>
<image src="{{touxiang}}" class="t"></image>
<view>{{nicheng}}</view>
<!-- 想要已进入页面就显示头像和昵称使用 open-type 标签 -->
<open-data type="userAvatarUrl"></open-data>
<open-data type="userNickName"></open-data>
<!-- 使用语言 -->
<open-data type="userLanguage"></open-data>
data: {
msg: 'csgo',
touxiang: "",
nicheng: ""
},
getuserInfo() {
wx.getUserProfile({
desc: '亲爱的宝贝', // 声明获取用户个人信息后的用途,后续会展示在d窗中,请谨慎填写
success: (res) => {
console.log(res)
let {
userInfo: {
avatarUrl,
nickName
}
} = res
this.setData({
nicheng: nickName,
touxiang: avatarUrl
})
}
})
},
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)