一、 前言
很多大型游戏里 都采用了虚拟摇杆 ,即 手触摸 屏幕 才出现 摇杆,一方面 使 玩家更易操作, 另一方面则是使得 游戏的视觉变得更加酷炫 。这一篇教程就告诉大家如何 完成制作 一个 虚拟摇杆。
二、 图片准备
笔者 不太精通ps,也没有费时间去画图了。只用了两个简单的有填充色的 圆形作为 摇杆的组成部分。 小圆代表摇杆,大圆代表摇杆的底座。
三、 一些构想
首先把这个摇杆定位为一个飞行射击游戏的摇杆。即摇杆需要实现 飞机主角的移动。
所以,大体上这就是一个点击屏幕会出现的虚拟摇杆。但是,考虑到一般飞行射击游戏 的玩家惯用 左手进行飞行操作,所以我们把点击出现虚拟摇杆的触摸区域定在左边的一块矩形 区域 。 屏幕右边的区域 用于 点击屏幕触摸 发射 子弹等 功能性 道具使用。
这里又有一个问题。
一个固定大小的虚拟摇杆 可能会 不能满足玩家的需要。 不少玩家在 操纵摇杆时 手指会超出摇杆的范围(这也是玩游戏的人之常情嘛,总不能 让别人 正激动的时候 就 不让别人 操纵的摇杆了吧 。)
四、代码实现
想到这里我就先直接上代码了吧。。
#ifndef __YAOGAN_SCENE_H__
#define __YAOGAN_SCENE_H__
#include "cocos2d.h"
#include "SimpleAudioEngine.h"
using namespace cocos2d;
class Yaogan : public cocos2d::CCLayer
{
public:
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
CCSprite* jianpan_back;
CCSprite* jianpan;
int press_type ;//0-still 1-up 2-down 3-left 4-right
float anchor_bx;
float anchor_by;
float anchor_x;
float anchor_y;
virtual bool init();
// there's no 'id' in cpp, so we recommand to return the exactly class pointer
static cocos2d::CCScene* scene();
// a selector callback
//check whether the yaogan can be show according to its coordinate;
bool check_Can_Be_Show(CCPoint point);
int is_Still_Pressed(CCPoint point);
void set_Yaogan_Place(CCPoint point);
void set_inner_Yaogan_Place(CCPoint point);
void menuCloseCallback(CCObject* pSender);
void backgroundRoll(float);
void backgroundRoll();
void initWithJianpan();
void ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
void ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
void ccTouchesMoved(CCSet *pTouches , CCEvent *pEvent);
// implement the "static node()" method manually
CREATE_FUNC(Yaogan);
//计算出x、y方向的位移。
float calculate_Move_X( float x );
float calculate_Move_Y( float y );
void controll_Plane();
};
#endif // __YAOGAN_SCENE_H__
下面来详细讲解一下 代码的实现。
bool Yaogan::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
initWithJianpan();
this->setTouchEnabled(true);
return true;
}
void Yaogan::initWithJianpan(){
CCSize size = CCDirector::sharedDirector()->getWinSize();
jianpan = CCSprite::create("jianpan2.png");
jianpan_back = CCSprite::create("jianpan.png");
jianpan->setPosition(ccp(size.width/6,size.height/4));
jianpan_back->setPosition(ccp(size.width/6,size.height/4));
this->addChild(jianpan,2);
this->addChild(jianpan_back,1);
anchor_bx = anchor_x = size.width / 6;
anchor_by = anchor_y = size.height / 4;
}
首先是ccscene的初始化,在调用父类的init 函数后 ,设置这个layer 可触摸。也调用initjianpan() 把 虚拟键盘。
initjianpan 这是把 大图和小图都加载到层中。(要记得 设置visibility 为false 哦)
void Yaogan::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent){
CCTouch *touch = dynamic_cast<CCTouch*>( pTouches->anyObject() );
float x = touch->getLocation().x;
float y = touch->getLocation().y;
CCLog("inner_touch %f %f",x,y);
//判断是否展现摇杆
if(check_Can_Be_Show(ccp(touch->getLocation().x,touch->getLocation().y))){
this->setVisible(true);
set_Yaogan_Place(ccp(touch->getLocation().x,touch->getLocation().y));
}
//````
}
void Yaogan::ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent){
this->setVisible(false);
}
void Yaogan::ccTouchesMoved(CCSet *pTouches , CCEvent *pEvent){
if( this->isVisible() ){
CCTouch* touch = dynamic_cast<CCTouch*>( pTouches->anyObject() );
int press_rs = is_Still_Pressed(ccp(touch->getLocation().x,touch->getLocation().y)) ;
if( press_rs == 1 ){
this->set_inner_Yaogan_Place(ccp(touch->getLocation().x,touch->getLocation().y));
}else if( press_rs == 2 ){
float x,y;
x = y = 0.0f;
if(touch->getLocation().y == anchor_by){
y = anchor_by;
if( touch->getLocation().x > anchor_bx ){
x = anchor_bx + jianpan_back->getContentSize().width / 2 - jianpan->getContentSize().width / 2;
}else{
x = anchor_bx - jianpan->getContentSize().width / 2 + jianpan->getContentSize().width / 2;
}
}else if(touch->getLocation().x == anchor_bx){
x = anchor_bx;
if( touch->getLocation().y > anchor_by ){
y = anchor_bx + jianpan_back->getContentSize().height / 2 - jianpan->getContentSize().height / 2;
}else{
y = anchor_bx - jianpan->getContentSize().height / 2 + jianpan->getContentSize().height / 2;
}
}else{
float k = ( touch->getLocation().y - anchor_by ) /
( touch->getLocation().x - anchor_bx );//计算斜率
x = touch->getLocation().x;
y = touch->getLocation().y;
float r_pingfang = ( jianpan_back->getContentSize().width / 2
- jianpan->getContentSize().width / 2 ) * ( jianpan_back->getContentSize().width / 2 - jianpan->getContentSize().width / 2 );
if( x < anchor_bx ){
float t = r_pingfang / ( 1 + k * k );
t = sqrt(t);
x = anchor_bx - t;
if( y < anchor_by ){
y = anchor_by - t * k;
}else{
y = - t * k + anchor_by ;
}
}else{
float t = r_pingfang / ( 1 + k * k );
t = sqrt(t);
x = anchor_bx + t;
if( y < anchor_by ){
y = anchor_by + t * k;
}else{
y = t * k + anchor_by;
}
}
}
this->set_inner_Yaogan_Place(ccp( x , y ));
}else{
this->setVisible(false);
}
}
}
三个 与触摸有关的函数
end 函数,把这层设置为不可见。
begin函数,判断是否在 指定区域内的触摸,如果在就 设置该层出现,并 设置图片的位置。
move函数,判断 是否还在需要的触摸 范围内 如果在 就 计算 x,y的位移。最大时 x平方+y平方 = r 平方。
bool Yaogan::check_Can_Be_Show(CCPoint point){
CCSize size = CCDirector::sharedDirector()->getWinSize();
float x = point.x;
float y = point.y;
if(
x <= size.width / 3 && x > jianpan_back->getContentSize().width / 2
&&
y < size.height / 1.75 && y > size.height / 4
){
return true;
}
return false;
}
int Yaogan::is_Still_Pressed(CCPoint point){
float x = point.x;
float y = point.y;
if( (x - anchor_bx) * (x - anchor_bx) + (y - anchor_by) * (y - anchor_by) <
( jianpan_back->getContentSize().width / 2 - jianpan->getContentSize().width / 2 ) *
( jianpan_back->getContentSize().width / 2 - jianpan->getContentSize().width / 2 )
){
return 1;
}
else if(
(x - anchor_bx) * (x - anchor_bx) + ( y - anchor_by ) * ( y - anchor_by )
<
jianpan_back->getContentSize().width * jianpan_back->getContentSize().width * 4
&&
(x - anchor_bx) * (x - anchor_bx) + (y - anchor_by) * (y - anchor_by) >=
( jianpan_back->getContentSize().width / 2 - jianpan->getContentSize().width / 2 ) *
( jianpan_back->getContentSize().width / 2 - jianpan->getContentSize().width / 2 )
){
return 2;
}
return 0;
}
两个判断重合的函数。
本期的教你打灰机就到此结束了,欢迎大家多交流>.<