水果忍者pc版

       欢迎大家加入这个水果忍者pc版问题集合的讨论。我将充分利用我的知识和智慧,为每个问题提供深入而细致的回答,希望这能够满足大家的好奇心并促进思考。

1.切水果PC版?一运行就白屏?然后自动退出?求解决!

水果忍者pc版

切水果PC版?一运行就白屏?然后自动退出?求解决!

       关于PC版切水果,有的玩家打开游戏,发现白屏,然后进入游戏,出现了游戏的画面,但是立刻就弹出来了,嗯,放心,不是游戏文件有问题,也不是缺少什么组件,也不是电脑中毒了,而是你的显卡有点淘汰了,所以导致游戏无法运行。

       不过不要灰心,去网上下载一个

       3d-analyze2.36b

       软件,现在有汉化版的。

       下好后,解压,运行3DAnalyze2.36b.exe,出现一个界面,点击选择程序----》击水果忍者运行的EXE文件----》硬件限制,模拟硬件TnL加速勾上----》运行程序。

       这个时候就可以玩了,你快去试试吧。

        最近Kinect连接Xbox玩水果忍者的视频非常红火,可惜小斤只有本本和Kinect,没法玩Xbox上的体感游戏。幸运的是,寻寻觅觅后,小斤发现水果忍者有PC版本,既然上一个教程我们已经可以让Kinect认出我们手势,在这基础上,我们用手来控制鼠标,就可以在PC上玩咯!

       视频地址:/v_show/id_XMjk2OTU3MjYw.html,徒手切还需要多练练。

       上个教程,我们通过RaiseHand来捕捉举起后手的位置,于是小斤决定,用RaiseHand来触发鼠标移动事件,用Click来触发鼠标单击,但测试结果不让人满意,鼠标移动一卡一卡的,原因是RaiseHand识别需要时间,达不到实时的标准,怎么办呢?小斤翻阅了OpenNI的文档,找到了tracking的相关API。这样,在我们识别出手后,使用跟踪的办法得到手的实时位置,移动鼠标的问题迎刃而解!这就好比在茫茫人海中,跟着一个人走比找到一个人更容易!

        因为这个教程代码量稍微多了点,小斤就不一股脑全抛上来了,先上主函数,再解释回调函数。

1程序执行后,窗体和显示和上一个手势识别的例程是一样的,由于要使用mouse_event来控制鼠标,小斤选择了MFC框架,主要是一个Dialog和一个按钮。由于我们的程序执行时,是使用OpenCV的highgui进行图像显示的,这里点击窗体上按钮后创建并开始线程,线程函数KinectGestureMain(),也就是这里的主函数。

       2KinectGestureMain()中的内容,大部分和上一个例程是一样的,在2这里,小斤创建了一个HandsGenerator,这个生成器主要帮我们负责跟踪的工作。它的创建方法和其它的生成器是一样的,传一个Context给Create()方法

       3与GestureGenerator类似,我们需要为HandsGenerator注册回调函数,

       [cpp]?view plain?copy

       XnStatusxn::HandsGenerator::RegisterHandCallbacks?(?HandCreate?CreateCB,?HandUpdate?UpdateCB,?HandDestroy?DestroyCB,?void?*?pCookie,?XnCallbackHandle?&?hCallback?)

        其中定义HandCreate是一个新的手(跟踪)被创建时调用的,HandDestroy 则相反,在手消失后被调用,UpdateCB在手变化位置时被调用。另外,pCookie是传给回调函数的指针,可以放一些用户数据,小斤把程序的画板图像指针传入,这样可在回调函数中直接绘图了。phCallback是一个回调函数的handle,可用来注销回调函数。

       4这边设定了,按m键,进入鼠标控制模式。

        其它代码都和上一个例程差不多,我们来看看回调函数。

[cpp]?view?plain?copy

       //?callback?function?for?gesture?recognized?

       void?XN_CALLBACK_TYPEGRecognized(?xn::GestureGenerator?&generator,?

const?XnChar?*strGesture,?

const?XnPoint3D?*pIDPosition,?

const?XnPoint3D?*pEndPosition,?

void?*pCookie?)?

       {?

       int?imgStartX=0;?

       int?imgStartY=0;?

       int?imgEndX=0;?

       int?imgEndY=0;?

       //5?

       imgStartX=(int)(640/2-(pIDPosition->X));?

       imgStartY=(int)(480/2-(pIDPosition->Y));?

       imgEndX=(int)(640/2-(pEndPosition->X));?

       imgEndY=(int)(480/2-(pEndPosition->Y));?

       IplImage*?refimage=(IplImage*)pCookie;?

       if(strcmp(strGesture,"Wave")==0)?

       {?

       cvLine(refimage,cvPoint(imgStartX,imgStartY),cvPoint(imgEndX,imgEndY),CV_RGB(255,255,0),6);?

       //6?

       handsGenerator.StartTracking(*pEndPosition);?

       }?

       else?if(strcmp(strGesture,"Click")==0)?

       {?

       cvCircle(refimage,cvPoint(imgStartX,imgStartY),6,CV_RGB(0,0,255),12);?

       //7?

       if(isRealMouseControl)?

       {?

       messageHandler(cvPoint(imgStartX,imgStartY),0,REAL_MOUSE_CLICK);?

       }?

       }?

       }?

       //?callback?function?forgesture?progress?

       void?XN_CALLBACK_TYPEGProgress(?xn::GestureGenerator?&generator,?

       const?XnChar?*strGesture,?

       const?XnPoint3D?*pPosition,?

       XnFloat?fProgress,?

       void?*pCookie?)?

       {?

       }

       5由于pIDPosition和pEndPosition的坐标,是以屏幕中心为(0,0)点的坐标系,在OpenCV中的显示,是以屏幕左上角为(0,0)点,所以这里做了一个转换。

       6这一段代码,我们的GestureGenerator识别出“挥动”手势后,调用了HandsGenerator的StartTracking()方法来开始在pEndPosition这个位置跟踪手,pEndPosition便是“挥动”“手势的结束位置。

       7中,如果识别出了“前推”手势,并开启了鼠标控制模式,就调用小斤定义的messageHandler()方法模拟鼠标点击。这个messageHandler()待会会在AppMessage.cpp中实现。

接着,小斤实现了Hands相关的回调函数:

[cpp]?view?plain?copy

       //8?

       void?XN_CALLBACK_TYPEHand_Create(xn::HandsGenerator&?generator,XnUserID?nId,const?XnPoint3D*pPosition,?XnFloatfTime,?void*pCookie)?

       {?

       addTrackingId(nId);?

       }?

       void?XN_CALLBACK_TYPEHand_Update(xn::HandsGenerator&?generator,XnUserID?nId,const?XnPoint3D*pPosition,?XnFloatfTime,?void*pCookie)?

       {?

       int?imgPosX=0;?

       int?imgPosY=0;?

       char?locationinfo[100];?

       imgPosX=(int)(640/2-(pPosition->X));?

       imgPosY=(int)(480/2-(pPosition->Y));?

       IplImage*?refimage=(IplImage*)pCookie;?

       cvSetImageROI(refimage,cvRect(40,450,640,30));?

       CvFont?font;?

       cvInitFont(?&font,CV_FONT_VECTOR0,1,?1,?0,?3,?5);?

       cvSet(refimage,cvScalar(255,255,255));?

       if(isRealMouseControl)?

       {?

       sprintf(locationinfo,"MouseCtrl:?%dth?HandLoc:?%d,%d",nId,(int)pPosition->X,(int)pPosition->Y);?

       }?

       else?

       {?

       sprintf(locationinfo,"Normal:?%dth?HandLoc:?%d,%d",nId,(int)pPosition->X,(int)pPosition->Y);?

       }?

       cvPutText(refimage,locationinfo?,cvPoint(30,30),?&font,?CV_RGB(0,0,0));?

       cvResetImageROI(refimage);?

       CvPoint?thisLocation=cvPoint(imgPosX,imgPosY);?

       //9?

       if(isRealMouseControl)?

       {?

       //cvCircle(refimage,cvPoint(imgPosX,imgPosY),1,CV_RGB(255,0,0),2);?

       messageHandler(thisLocation,nId,REAL_MOUSE_MOVE);?

       }?

       else?

       {?

       cvCircle(refimage,cvPoint(imgPosX,imgPosY),1,CV_RGB(255,0,0),2);?

       }?

       }?

       void?XN_CALLBACK_TYPEHand_Destroy(xn::HandsGenerator&?generator,XnUserID?nId,XnFloat?fTime,void*?pCookie)?

       {?

       //printf("Lost?Hand:?%d\n",?nId);?

       removeTrackingId(nId);?

       }

       8中的Hand_Create()就是CreateCB,该回调函数定义如下:

       [cpp]?view plain?copy

       void?XN_CALLBACK_TYPEHand_Create(xn::HandsGenerator&?generator,XnUserID?nId,const?XnPoint3D*pPosition,?XnFloatfTime,?void*pCookie)?

        其中,generator指定触发Hands的生成器。

        nId为被创建的手(跟踪)的id,这个id会随着手的不断创建和消失增加,用以标识每一个手。

        pPosition是手当前的位置,fTime是一个Timestamp,而pCookie就是用户传入的数据指针了。

        在该方法中,小斤使用了自己定义的addTracking()方法,该方法也在AppMessage.cpp中实现。小斤在该文件中维护了一个数组,用以标识每个id的手是否在跟踪状态。

       9Hand_Update()和Hand_Destroy()的参数和Hand_Create()是一样的,除去一堆绘图过程之外,小斤使用messageHandler()方法模拟鼠标移动。

       以下是AppMessage.cpp的内容:

[cpp]?view?plain?copy

       #include?"AppMessage.h"?

       //Location?and?move?anglelast?time?for?each?userId(Hand?Id)?

       CvPoint?lastLocation[MAX_HAND_NUM];?

       int?isHandTracking[MAX_HAND_NUM]={0};?

       int?isClickDown=0;?

       void?addTrackingId(int?userId)?

       {?

       isHandTracking[userId]=1;?

       }?

       void?removeTrackingId(int?userId)?

       {?

       isHandTracking[userId]=0;?

       }?

       CvPoint?getLastLocation(int?userId)?

       {?

       return?lastLocation[userId];?

       }?

       void?messageHandler(CvPoint?&location,int?userId,int?flag)?

       {?

       //initialize?the?lastLocation?from?the?location?obtained?bythe?first?time?

       if(lastLocation[userId].x==0&&lastLocation[userId].y==0)?

       {?

       lastLocation[userId].x=location.x;?

       lastLocation[userId].y=location.y;?

       }?

       if(flag==REAL_MOUSE_CLICK)?

       {?

       if(!isClickDown)?

       {?

mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);?

       }?

       else?{?

mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0);

       }?

       isClickDown=1-isClickDown;?

       }?

       else?if(flag==REAL_MOUSE_MOVE)?

       {?

       //10?

       int?firstHandId=-1;?

       for(int?i=0;i<MAX_HAND_NUM;i++)?

       {?

if(isHandTracking[i]!=0)?

{?

if(firstHandId==-1)?

{?

firstHandId=i;?

break;?

}?

}?

       }?

       if(abs(location.x-lastLocation[userId].x)<5)?

       {?

location.x=lastLocation[userId].x;?

       }?

       if(abs(location.y-lastLocation[userId].y)<5)?

       {?

location.y=lastLocation[userId].y;?

       }?

       //11?

       if(userId==firstHandId)?

       {?

mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE,?

(location.x-160)*65536/640*2,(location.y-120)*65536/480*2,0,0);?

       }

       }?

       lastLocation[userId].x=location.x;?

       lastLocation[userId].y=location.y;?

       }

       10根据程序维护的isHandTracking数组,找到被跟踪的第一个手。

       11考虑到可能有多个手被捕捉并跟踪的情况,先来先得,这里小斤让鼠标只听第一个出现的手的指挥,进行移动。

        这里使用了MOUSEEVENTF_ABSOLUTE,所谓的绝对坐标,就是把计算机屏幕定义为65536*65536个点的坐标系。如果分辨率为640*480,想把鼠标移动到屏幕正中,就可以调用mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE,320/640*65536,240/480*65536,0,0);

        这段代码中,由于OpenNI输出的分辨率为640*480,而小斤习惯抬起右手来切水果,所以只使用了右半边区域来控制鼠标,同时做了些微调,大家可以根据自己的喜好来设置。

        另外,在水果忍者PC版中,切的动作是按住鼠标左键(MOUSE_LEFTDOWN)并移动(MOUSE_MOVE)来触发的。因此,小斤在程序中使用push手势来切换MOUSE_LEFTDOWN和MOUSE_LEFTUP。

        使用方法如下:打开程序,按下M键进入鼠标控制模式,进入游戏后,push一下,使鼠标处于MOUSE_LEFTDOWN状态,屏幕就会出现刀光剑影咯,不想玩的时候,再push一下即可。

        好了,小斤要去切几盘水果休息一下咯,希望这篇文章对大家有所帮助和启发。

       今天关于“水果忍者pc版”的探讨就到这里了。希望大家能够更深入地了解“水果忍者pc版”,并从我的答案中找到一些灵感。