c语言制作一个简单的打字游戏(落下一个字母按相应字母消去,记录分数)

c语言制作一个简单的打字游戏(落下一个字母按相应字母消去,记录分数),第1张

游戏常量参数自行修改(字母的列数,下落最大高度,下落速度等)。

程序功能:(随机生成字母,下落,并检查按键,计分)

多线程按键检查采用新的线程与主线程同步。

独立速度:每个字母下落速度都是随机且不相同。

玩法:按键区分大小写,落到底部或被玩家按中,下落中的字母就会消失,并在该梁粗列顶部创建新的字母下落,按中1次记1分。

注意:由于字母都是随机的,如果同时下落的字母很多,可能会有重复字母出现,如果按键对应了多个同样的字母,这些字母会删掉并新建,也就是说出现按中一次记多分,说明有多个重复字母,不是BUG!

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>

#include <conio.h>

#include <time.h>

#include <windows.h>

#define W 30//宽度

#define H 20//高度

#define MinSPEED 50//最慢下降速度(周期,数字越小越快)

#define MAXSPEED 5//最快下降速度

int score=0//总分

typedef struct letter

{

     int ascii// 字母ASCII码

     int hIndex//对应打印数组行下标

     int wIndex//对应打印数组列下标

     int cnt//周期计数,当cnt==speed,hIndex++并且cnt重新置0

     int speed//下降速度

     int key//0表示没有橡返镇被按中,1表示被按中

     struct letter *next

}LETR

void meError(void *p)//内存申请失败

LETR *newLETR(LETR *letrHead,LETR*letrTail,int wIndex)//产生一个新的字母,并添加到链表,返回尾节点

LETR* delLETR(LETR *letrHead,LETR*letrTail,int wIndex)//删除列下标的字母节点,返回新的尾节点

LETR *init(LETR *letrHead)//初始化一组字母,返回链表尾节点

LETR *showList(LETR *letrHead,LETR*letrTail)//显示列表并检查,发现到底或被按键按中的字母删除并新建新的字母,返回新的尾节点

void runLetter(LETR *letrHead)//所有字母一周期计数

DWORD WINAPI checkKey(LPVOID lpParameter)//新线程

int main()

{

   世旁 int i

    LETR *letrHead=NULL,*letrTail=NULL

    letrHead=(LETR *)malloc(sizeof(LETR))

    meError(letrHead)

    letrHead->next=NULL

    srand(time(NULL))

    letrTail=init(letrHead)

    CreateThread(NULL,0,checkKey,letrHead,0,NULL)

    letrTail=showList(letrHead,letrTail)

    while(1)

    {

        system("cls")

        printf("总分:%d\n",score)

        for(i=0i<Wi++)

            printf("-")

        printf("\n")

        runLetter(letrHead)

        letrTail=showList(letrHead,letrTail)

        for(i=0i<Wi++)

            printf("-")

        printf("\n")

    }

    return 0

}

DWORD WINAPI checkKey(LPVOID lpParameter)

{

char c

LETR *letrHead=NULL

while(1)

    {

        letrHead=(LETR *)lpParameter

        c=getch()

        while(letrHead->next)

        {

            if(c==letrHead->next->ascii)

                letrHead->next->key=1,score++//按键标识置1,考虑可能有多个相同随机字母,故用标识,在显示函数统一删除并新建

            letrHead=letrHead->next

        }

    }

return 0

}

void runLetter(LETR *letrHead)//所有字母一周期计数

{

    while(letrHead->next)

    {

        if(letrHead->cnt<letrHead->speed)

            letrHead->cnt++

        else

            (letrHead->next->hIndex)++,letrHead->cnt=0

        letrHead=letrHead->next

    }

}

LETR *showList(LETR *letrHead,LETR*letrTail)//显示列表并检查,发现到底或被按键按中的字母删除并新建新的字母,返回新的尾节点

{

    int i,j,wIndex

    char sp[H][W]

    LETR *head=letrHead

    for(i=0i<Hi++)

        for(j=0j<Wj++)

            sp[i][j]=' '

    while(letrHead->next)

    {

        if(letrHead->next->hIndex>H-1 || letrHead->next->key==1)//到底或者被按中就删除并新建,重新循环

        {

            wIndex=letrHead->next->wIndex

            letrTail=delLETR(head,letrTail,wIndex)

            letrTail=newLETR(head,letrTail,wIndex)

            letrHead=head

        }

        else

            sp[letrHead->next->hIndex][letrHead->next->wIndex]=letrHead->next->ascii

        letrHead=letrHead->next

    }

    for(i=0i<Hi++,printf("\n"))

        for(j=0j<Wj++)

            printf("%c",sp[i][j])

    return letrTail

}

LETR *init(LETR *letrHead)//初始化一组字母,返回链表尾节点

{

    int i

    LETR*letrTail=NULL

    for(i=0i<Wi++)

        letrTail=newLETR(letrHead,letrTail,i)

    return letrTail

}

LETR *newLETR(LETR *letrHead,LETR*letrTail,int wIndex)//在列下标wIndex首行,产生一个新的字母,并添加到链表,返回尾节点

{

    int n

    LETR *leterNEW=(LETR *)malloc(sizeof(LETR))

    meError(leterNEW)

    leterNEW->next=NULL

    n=rand()%2

    if(n)//随机大小写

        leterNEW->ascii=rand()%26+65//随机一个大写字母

    else

        leterNEW->ascii=rand()%26+97//随机一个小写字母

    leterNEW->hIndex=0

    leterNEW->wIndex=wIndex

    leterNEW->cnt=0

    leterNEW->speed=rand()%(MinSPEED-MAXSPEED)+1+MAXSPEED

    leterNEW->key=0

    if(letrHead->next==NULL)

        letrHead->next=leterNEW

    else

        letrTail->next=leterNEW

    letrTail=leterNEW

    return letrTail

}

LETR* delLETR(LETR *letrHead,LETR*letrTail,int wIndex)//删除列下标的字母节点,返回新的尾节点

{

    LETR *lhead=letrHead,*letrDel=NULL

    while(letrHead->next)

    {

        if(letrHead->next->wIndex==wIndex)

        {

            letrDel=letrHead->next

            letrHead->next=letrHead->next->next

            free(letrDel)

            break

        }

        letrHead=letrHead->next

    }

    letrHead=lhead

    while(letrHead->next)//重置尾节点

        letrHead=letrHead->next

    return letrHead

}

void meError(void *p)//内存申请失败

{

    if(p==NULL)

    {

        printf("\n异常:内存申请失败!回车结束程序!\n")

        while(getch()!='\r')

        exit(0)

    }

}

/*

游戏开始,从天上掉下10个有标号(字母)的炸d,

下面有10颗子d(就是可以按10个羡伏字母).

如果所按字母包含在炸d中,就找到兄银携相应的炸d并

消灭它,消灭后返回继续利用.如果没有就一直飞到天上最后才返回.

*/

import java.net.*

import java.awt.*

import java.awt.event.*

import java.applet.*

import javax.swing.*

public class paodan extends Applet implements Runnable,KeyListener

{

private Image bgImage

private Graphics bg

static Thread myThread

static AudioClip ac1,ac2

static JFrame md

String Zi26=""

String pd[]={"a","a","a","a","a","a","a","a","a","a"}//用来存储10个字母做落下的炮d

String fj[]={"","","","","","","","","",""}//用来存储10个字母做反击的防搏罩空

int x[]=new int[10]

int y[]=new int[10]

//炸d的坐标

int x1[]=new int[10]

int x2[]=new int[10]

int y1[]=new int[10]

//火箭的坐标

int life=100 //生命

Toolkit KIT=this.getToolkit()

Image paodan=KIT.createImage("paodan.jpg")

Image huojian=KIT.createImage("huojian.jpg")

public paodan() //用来生成一个包含26个英文字母的字符串Zi26

{for (int i=0i<26i++)

Zi26+=(char)((int)'A'+i)

}

public void cushi() //初始各种数据,如炮d与火箭的坐标.

{

try

{URL u1=this.getClass().getResource("huishou.wav")

URL u2=this.getClass().getResource("lanjie.wav")

ac1=Applet.newAudioClip(u1)

ac2=Applet.newAudioClip(u2)

}catch(Exception e){}

for (int i=0i<10i++)

{pd[i]=noRepeat()

x[i]=noHit(i,10)

if (i>=5)

y[i]=5+(int)(Math.random()*50)

else

y[i]=60+(int)(Math.random()*50)

x1[i]=220+i*32+1y1[i]=550

x2[i]=x1[i]

}

}

public void panduan() //用来判断pd[i]的y值是否要到达屏幕下边,如果是就把Y值变为5,并把所有Y值加3.

{ for(int i=0i<10i++)

{ if (y[i]>=500)

{life--ac1.play()y[i]=5}

y[i]+=3

if (life==0) System.exit(0)

}

y[9]+=3

md.setTitle("打字训练室你的生命为"+life+" 提示:白色的字母表示未按,粉红色的表示已按.")

}

public void fk() //防空程序,用来击毁落下的炸d

{ int i=0,j=0

for (i=0i<10i++)

{ if (!fj[i].equals(""))

{

for (j=0j<10j++)

if (fj[i].equals(pd[j]))

{ if (!(x1[i]>=x[j] &&x1[i]<=x[j]+32 || x1[i]+32>=x[j] &&x1[i]+32<=x[j]+32))

if (x1[i]>x[j])

x1[i]-=4

else x1[i]+=4

if (!(y1[i]>=y[j] &&y1[i]<=y[j]+32 || y1[i]+32>=y[j] &&y1[i]+32<=y[j]+32))

if (y1[i]>y[j])

y1[i]-=3

else y1[i]+=4

if (y[j]>=380 &&Math.abs(x[j]-x1[i])>5)

if (x[j]>x1[i]) x1[i]+=5

else if (x[j]<x1[i]) x1[i]-=5

if (y[j]>=380 &&Math.abs(y[j]-y1[i])>5)

if (y[j]>y1[i]) y1[i]+=5

else if (y[j]<y1[i]) y1[i]-=5

if ((x1[i]>=x[j] &&x1[i]<=x[j]+32 || x1[i]+32>=x[j] &&x1[i]+32<=x[j]+32) &&(y1[i]>=y[j] &&y1[i]<=y[j]+32 || y1[i]+32>=y[j] &&y1[i]+32<=y[j]+32))

{life++ac2.play()pd[j]=noRepeat()x[j]=noHit(i,10)y[j]=5x1[i]=x2[i]y1[i]=550fj[i]=""}

break

}

if (j==10) y1[i]-=3

if (y1[i]<=5) {y1[i]=550fj[i]=""}

}

}

}

public void paint(Graphics g)

//根据相应的坐标在屏幕上画炸d和吃炸d的娃娃,并保证白色的字母表示未按,粉红色的表示已按

{int i=0,j=0

g.setFont(new Font("Vrinda",1,21))

for(i<pd.lengthi++)

{ for (j=0j<fj.lengthj++)

if (pd[i].equals(fj[j]))

{g.setColor(new Color(255,93,55))

g.drawImage(paodan,x[i],y[i],this)

g.drawString(pd[i],x[i]+11,y[i]+20)

break

}

if (j==fj.length)

{g.setColor(new Color(255,255,255))

g.drawImage(paodan,x[i],y[i],this)

g.drawString(pd[i],x[i]+11,y[i]+20)

}

g.setColor(new Color(255,93,55))

g.drawImage(huojian,x1[i],y1[i],this)

g.drawString(fj[i],x1[i]+10,y1[i]+22)

}

}

//没有按的显红色,按了的显白色

public void keyPressed(KeyEvent k) //当用户按的是字母时,就生成一个防空字母.

{char z=k.getKeyChar()

int i=0,j=0

if ((z>='A' &&z<='Z') || (z>='a' &&z<='z'))

{ if (z-32>=65) z-=32

String zc=""+z

for(i<fj.lengthi++)

{ if (zc.equals(fj[i])) break

} //保证字母不重复

if (i==fj.length)

for(i=0i<fj.lengthi++)

if (fj[i].equals("")) {fj[i]=zcbreak}

}

}

public void keyReleased(KeyEvent k){}

public void keyTyped(KeyEvent k){}

public String noRepeat() //生成一个不重复的字母.

{int zc,i

String xinx

while(true)

{zc=(int)(Math.random()*26)

xinx=Zi26.substring(zc,zc+1)

for(i=0i<10i++)

if (pd[i].equals(xinx)) break

if(i==10) return xinx

}

}

int noHit(int i,int langth) //让字母保持车距.

{int tmpX,j,k,width=32

while (true)

{ tmpX=(int)(Math.random()*768)+1

for(j=0j<10j++)

{ if (tmpX+width<x[j] || tmpX>x[j]+width) continue//如果欲生成的位置不与当前J所占的位置相交就判断下一个J.

if ((tmpX>=x[j] &&tmpX<=x[j]+width) || (tmpX+width>=x[j] &&tmpX+width<=x[j]+width)) break

//如果欲生成的位置与当前x[j]所占据的范围相交就结束循环,重新生成一个起始位置.

}

if (j==10) {return tmpX}

}

}

public void update(Graphics g)

{if (bgImage==null)

{bgImage=createImage(this.getSize().width,this.getSize().height)

bg=bgImage.getGraphics()

}

bg.setColor(getBackground())

bg.fillRect(0,0,this.getSize().width,this.getSize().height)

//bg.setColor(getForeground())

paint(bg)

g.drawImage(bgImage,0,0,this)

}

public void run() //用线程循环更改Y值,并根据新的坐标在屏幕上重画pd[I]

{

while(true)

{fk()

panduan()

repaint()

try{ myThread.sleep(50) }catch(Exception e) {}

}

}

public static void main(String args[])

{paodan m=new paodan()

md=new JFrame("打字训练室")

md.setSize(800,600)

md.addKeyListener(m)

md.getContentPane().add(m)

m.cushi()

md.setVisible(true)

md.setResizable(false)

myThread=new Thread(m)

myThread.start()

}

}

注:源代码取自编程中国

本人一点建议:其实你这样学Java是没用的,你应该知道你做的项目思想,先做什么后做什么,然后在亲自动手去敲代码!一点建议!


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/8262494.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-14
下一篇2023-04-14

发表评论

登录后才能评论

评论列表(0条)

    保存