Android游戏开发之Cocos2d-x

Android游戏开发之Cocos2d-x,第1张

游戏的制作如播放电影,拥有四大核心,包括: 导演、场景、图层、演员 。通过它们之间的不同配合,实现丰富多彩的效果。

public class CocosActivity extends AppCompatActivity {

private CCDirector mCcDirector

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState)

CCGLSurfaceView ccglSurfaceView =new CCGLSurfaceView(this)

setContentView(ccglSurfaceView)

导演,全局只有一个,单例模式创建

mCcDirector = CCDirector.sharedDirector()

开启绘制(开始拍电影)

mCcDirector.attachInView(ccglSurfaceView)

帧率,每秒刷新的次数,与手机性能有关

//ccDirector.setDisplayFPS(true)

设置帧率为60(记得把帧率文件放进项目中)

//ccDirector.setAnimationInterval(1/60f)

设置横屏

//ccDirector.setDeviceOrientation(CCDirector.kCCDeviceOrientationLandscapeLeft)

屏幕适配,会基于不同屏幕大小进行适配

mCcDirector.setScreenSize(1920,1080)

场景

CCScene ccScene = CCScene.node()

图层

CCLayer ccLayer =CCLayer.node()

给场景添加图层

ccScene.addChild(ccLayer)

导演运行场景

mCcDirector.runWithScene(ccScene)

}

@Override

protected void onResume() {

super.onResume()

mCcDirector.onResume()

}

@Override

protected void onPause() {

super.onPause()

mCcDirector.onPause()

}

@Override

protected void onDestroy() {

super.onDestroy()

mCcDirector.end()

}

1、平移

参数1是移动时间,参数2是目标位置坐标,ccp方法是把坐标转换为cocos2d的坐标

CCMoveTo ccMoveTo = CCMoveTo.action(3,ccp(200,0))

与上不同的是,第2个参数代表水平移动200,竖直不移动,即偏移量

CCMoveBy ccMoveBy =CCMoveBy.action(3,ccp(200,0))

2、旋转

参数1时间,参数2角度,旋转中心是左下角的点,顺时针转

CCRotateBy ccRotateBy =CCRotateBy.action(3,360)

与上不同的是,逆时针转(捷径,顺时针转270==逆时针转90)

CCRotateTo ccRotateTo =CCRotateTo.action(3,270)

3、缩放

参数1时间,参数2X方向缩放,参数3Y方向缩放

CCScaleBy ccScaleBy =CCScaleBy.action(3,2,2)

参数1时间,参数2缩放

CCScaleTo ccScaleTo =CCScaleTo.action(3,2)

4、跳跃(参数1时间,参数2目标点,参数3跳跃高度,参数4跳跃次数)

CCJumpBy ccJumpBy =CCJumpBy.action(3,ccp(0,0),100,3)

5、淡入淡出(参数是时间)

CCFadeIn ccFadeIn =CCFadeIn.action(2)

CCFadeOut ccFadeOut =CCFadeOut.action(2)

6、贝塞尔曲线

点的含义,从point1出发,经过point2,到达endPosition

CCBezierConfig ccBezierConfig =new CCBezierConfig()

ccBezierConfig. controlPoint_1 =ccp(100,50)

ccBezierConfig. controlPoint_2 =ccp(200,200)

ccBezierConfig. endPosition =ccp(300,100)

CCBezierBy ccBezierBy =CCBezierBy.action(2,ccBezierConfig)

7、加速度

CCMoveBy ccMoveBy =CCMoveBy.action(2,ccp(100,100))

渐快渐慢,参数2是加速度

CCEaseIn ccEaseIn =CCEaseIn.action( ccMoveBy ,5)

CCEaseOut ccEaseOut =CCEaseOut.action( ccMoveBy ,5)

8、闪烁(时间,闪烁次数)

CCBlink ccBlink =CCBlink.action(2,10)

9、文字(参1是显示的文字,参2是字体格式(可不填,如""),参数3是字体大小)

CCLabel ccLabel = CCLabel.labelWithString("显示文字","STCAIYUN.TTF",20)

设置文字颜色

ccColor3B ccColor3B =ccc3(100,50,0)

ccLabel.setColor(ccColor3B )

设置文字位置

ccLabel.setPosition(ccp(width,height))

重置文字

ccLabel.setString("显示文字")

颜色渐变(从本来的文字颜色渐变到设置的字体颜色)

CCTintBy tintBy =CCTintBy.action(3,ccc3(50,-50,100))

10、循环(参数是动画效果)

CCRepeatForever ccRepeatForever =CCRepeatForever.action(action)

11、延迟(参数是时间)

CCDelayTime ccDelayTime =CCDelayTime.action(1)

12、反转(将一个动画倒序执行)

ccJumpBy.reverse()

13、同时(参数是不定长度数组)

CCSpawn ccSpawn =CCSpawn.actions(action1,action2)

14、连续动画(参数是不定长度数组)

CCSequence ccSequence =CCSequence.actions(action1,action2, ccCallFunc ")

15、反射(执行一个动画方法)

CCCallFunc .action(this," anim ")

被反射的执行方法

public void anim (){} 

16、逐帧动画

public void walk(){

存放帧动画的集合

ArrayList ccSpriteFrames =new ArrayList<>()

String format="z_1_%d.png" // %d和%02d代表整数,用i来取代,%d只取代i,%02d会补0

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

CCSprite ccSprite =CCSprite.sprite(String.format(format,i))

CCSpriteFrame ccSpriteFrame =ccSprite.displayedFrame()

ccSpriteFrames.add(ccSpriteFrame )

}

参数1是动画名称,参数2是每一帧停留的时间,参数3是帧动画集合

CCAnimation ccAnimation =CCAnimation.animation("walk",.2f,ccSpriteFrames)

参数2是否持续执行动画,如果想执行无限循环,可以使用CCRepeatForever

CCAnimate ccAnimate =CCAnimate.action(ccAnimation,false)

mCcSprite.runAction(ccAnimate)

}

17、隐藏

CCHide ccHide =CCHide.action()

18、显示

CCShow ccShow =CCShow.action()

19、跟随(参数是跟随的对象)

CCFollow  ccFollow =CCFollow.action(mCCSprite)

20、执行动画(上述皆是)

mCcSprite.runAction(action)

21、工具类使用

CGPointUtil .distance(point1,point2)//计算两点距离

获取声音引擎

SoundEngine engine =SoundEngine.sharedEngine()

参数1是activity,SurfaceView创建时存入,参2是播放资源id(res\raw),参数3是否循环播放

engine.playSound(CCDirector.theApp,1,true)

手动停止音乐播放

engine.realesAllSounds()

生命周期跟随Activity

SoundEngine.sharedEngine().resumeSound()

SoundEngine.sharedEngine().pauseSound()

SoundEngine.sharedEngine().realesAllSounds()

预加载播放音乐,避免播放音乐时没声音

SoundEngine.sharedEngine().preloadEffect()

SoundEngine.sharedEngine().preloadSound()

1、创建

CCSprite mCcSprite =new CCSprite(" pic.jpeg ")

2、锚点(图片上的一点,类似图钉,对应图片显示的位置)

CGPoint cgPoint =ccp(0,0)

mCcSprite.setAnchorPoint(cgPoint)

3、位置

mCcSprite.setPosition(cgPoint)

4、属性(缩放、翻转、透明度)

ccSprite.setFlipX(true)水平翻转

ccSprite.setOpacity(255)透明度

ccSprite.setScale(2)缩放

5、移除(在Layer里面 *** 作)

mCcSprite.removeSelf() //精灵从图层中移除

( Layer )this.removeSelf()// 移除整个图层

6、尺寸

CGSize  cgSize =CCDirector.sharedDirector().winSize()

1、游戏暂停(图层静止,将不再响应任何事件)

MapLayer.this.onExit() 

注意:因为图层不再响应任何事件,所以暂停按钮应该加在暂停图层的父图层上

this.getParent().addChild(new PauseLayer())

2、游戏继续(图层恢复动态,接收点击事件)

MapLayer.this.onEnter() 

通用的游戏继续方法

CCDirector.sharedDirector().getRunningScene().onEnter()

3、定时器

CCScheduler ccScheduler =CCScheduler.sharedScheduler()

通过反射执行方法

ccScheduler.schedule(" onScheduler ",this,2,false)

方法声明为公开类型

public void  onScheduler (float f){ //实现具体逻辑

}

4、进度条

CCProgressTimer ccProgressTimer =CCProgressTimer.progressWithFile(" image/pic.jpeg ")//多层目录

ccProgressTimer.setPosition(width,height)

this.getParent().addChild(ccProgressTimer) //具体加到什么图层,看情况

ccProgressTimer.setScale(0.6f)

ccProgressTimer.setPercentage(2)

设置显示样式(垂直,水平)->(最后2个字母,left,right,代表进度条从左往右)

ccProgressTimer.setType(CCProgressTimer.kCCProgressTimerTypeHorizontalBar LR )

进度条外框 等元素,都作为精灵与进度条同级加入图层

this.getParent().addChild(sprite)

Android坐标系的(0,0)在左上角,而Cocos2d-x坐标系的(0,0)在左下角。所以在处理Android的点击事件MotionEvent时,需要进行坐标体系的转换。

CGPoint cgPoint = convertPrevTouchToNodeSpace (event)

监听图片的点击范围,自定义封装点击事件

CGRect .containsPoint( mCcSprite.getBoundingBox() , cgPoint )

CCMenu ccMenu =CCMenu.menu()

CCSprite normalSprite =CCSprite.sprite("pic_1.jpeg")//正常情况下显示的图片

CCSprite selectSprite =CCSprite.sprite("pic_2.jpeg")//按下时显示的图片

注意:反射的方法需要使用pulbic修饰,参数指target,直接传this,它不是上下文Context

CCMenuItemSprite itemSprite =CCMenuItemSprite.item( normalSprite , selectSprite , this ," onCLick ")

ccMenu.addChild( itemSprite )

this.addChild(ccMenu)//菜单添加到图层

public void onCLick (Object obj){}  //点击事件响应方法,必须用public修饰以及带参数

setIsTouchEnabled(true)//打开图层点击事件,默认关闭

模仿任何天气现象,只需要改这一句,剩下的不变

CCParticleSystem ccParticleSystem= CCParticleSnow.node()

设置雪花大小

ccParticleSystem.setScale(2)

设置飘落的速度

ccParticleSystem.setSpeed(10)

设置雪花的图片

ccParticleSystem.setTexture(CCTextureCache.sharedTextureCache().addImage("snow.png"))

this.addChild(ccParticleSystem,1)

停止粒子系统(下雪)

ccParticleSystem.stopSystem()

1、加载地图

 ArrayList mCGPoints = new ArrayList<>()

CCTMXTiledMap mCctmxTiledMap = CCTMXTiledMap.tiledMap(" map.tmx ")

mCctmxTiledMap.setAnchorPoint(ccp(0.5f,0.f))

mCctmxTiledMap.setPosition(width,height)

CCTMXObjectGroup cctmxObjectGroup= mCctmxTiledMap.objectGroupNamed("road") 

ArrayList<HashMap<String,String>>objects = cctmxObjectGroup.objects

for(HashMap<String,String>hashMap:objects){  //加载地图的坐标(需要经过的坐标点)

Integer x =Integer.parseInt(hashMap.get("x"))

Integer y =Integer.parseInt(hashMap.get("y"))

CGPoint cgPoint =ccp(x,y)

mCGPoints .add(cgPoint) }

this.addChild(mCctmxTiledMap)

在地图上添加精灵

mCCSprite.setPosition(mCGPoints.get(0))

mCctmxTiledMap.addChild(mCCSprite)

地图跟随精灵的移动而移动

CCFollow ccFollow =CCFollow.action(mCCSprite)

mCctmxTiledMap .runAction(ccFollow)

2、地图随手指触摸事件移动(重写触摸方法)

@Override

public boolean ccTouchesMoved(MotionEvent event) {

手指拖拽时,地图随手指移动

mCctmxTiledMap.touchMove(event,mCctmxTiledMap)

地图移动,地图上所有精灵都随之移动(地图是父亲,精灵是孩子)

mCctmxTiledMap.addChild(mCCSprite)

return super.ccTouchesMoved(event)

}

创建场景

CCScene ccScene =CCScene.node()

场景添加图层

ccScene.addChild(ccLayer)

场景切换特效

CCJumpZoomTransition ccJumpZoomTransition =CCJumpZoomTransition.transition(2,ccScene)

导演切换场景

CCDirector.sharedDirector(). replaceScene (ccJumpZoomTransition)

CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。用法和ArrayList相近。

CopyOnWriteArrayList copyOnWriteArrayList = new CopyOnWriteArrayList()

setIsTouchEnabled(true)//打开点击事件

@Override

public boolean ccTouchesBegan (MotionEvent event) {

return super.ccTouchesBegan(event)

}

@Override

public boolean ccTouchesCancelled (MotionEvent event) {

return super.ccTouchesCancelled(event)

}

@Override

public boolean ccTouchesMoved (MotionEvent event) {

return super.ccTouchesMoved(event)

}

@Override

public boolean ccTouchesEnded (MotionEvent event) {

return super.ccTouchesEnded(event)

}

描述:UI频繁刷新,造成主线程的堵塞或挂起

private CCGLSurfaceView mCCGLSurfaceView

mCCGLSurfaceView = (CCGLSurfaceView) CCDirector.sharedDirector().getOpenGLView()

mCCGLSurfaceView.queueEvent(new Runnable() {

@Override

public void run() { //切换到主线程

}

})

描述:CCSprite运行动画时,没有表现出任何视觉效果。

原因:一个动画只能被一个CCSprite执行一次,执行完成后,原来的动画会失效。

解决:每次执行的动画,都需要重新生成,即使是相同的动画效果。

缓存:CCDirector.sharedDirector().purgeCachedData()

步骤如下:

1.新建Cocos2d-win32工程,工程名为"TileGame",去除"Box2D"选项,勾选"Simple Audio Engine in Cocos Denshion"选项;

2.下载本游戏所需的资源,将资源放置"Resources"目录下;

3.使用Tiled工具制作地图。首先,下载开源的Tiled Map Editor工具,当前版本为0.8.1,建议使用QT版本。在Tiled工具,点击菜单栏→"文件"→"新文件",在d出的对话框中,填入如下内容:

地图方向分为:正常、45度。地图大小填入的是tile单位。块大小是资源每个tile的实际像素大小,在本篇中,使用32x32大小。点击"确定"。

4.接着,把所需要的tile集合加入到工具中。菜单栏→"地图"→"新图块",填入如下内容:

点击"浏览",选择"Resources"目录下的tmw_desert_spacing.png文件,会自动填充"名称"内容。块的宽高都为32像素。边距就是当前tile块开始计算实际像素时,应该跳过多少像素,宽高一样。间距就是两个tile块之间的像素距离,宽高一样。看看tmw_desert_spacing.png文件,可以看到每个tile块都1像素的黑色边框,这就是为什么要设置边距和间距为1像素。

点击"确定"。

5.可以看到tile块出现在"图块"窗口中。现在可以开始画地图。点击菜单栏→"视图"→"显示网格",可以开启网格参照线。点击工具栏"图章刷",然后在"图块"窗口点选一个tile块,接着在地图中,点击放入你所想要的位置。

用工具栏"填充",把地图背景填充成同一个tile块,这里为沙漠背景。可以从"图块"窗口点选多个tile块,可按Ctrl键多选,这样可以一次性将多个tile块放入地图中。进行制作地图,确保至少有一对建筑在地图上,因为后面需要一些东西来做碰撞。一旦完成了地图的制作,双击"图层"窗口中的当前层"块层 1",重命名为"Background"。然后点击工具栏"保存",命名为"TileMap.tmx",保存在"Resources"目录下。

6.将Tile地图加入到场景中。在HelloWorldScene.h文件中,添加如下代码:

CC_SYNTHESIZE_RETAIN(cocos2d::CCTMXTiledMap*, _tileMap, TileMap)

CC_SYNTHESIZE_RETAIN(cocos2d::CCTMXLayer*, _background, Background)

在HelloWorldScene.cpp文件中,构造函数添加如下:

HelloWorld::HelloWorld()

{

_tileMap = NULL

_background = NULL

}

初始化init函数,修改如下:

bool HelloWorld::init()

{

bool bRet = false

do

{

CC_BREAK_IF(! CCLayer::init())

this->setTileMap(CCTMXTiledMap::create("TileMap.tmx"))

this->setBackground(_tileMap->layerNamed("Background"))

this->addChild(_tileMap, -1)

bRet = true

} while (0)

return bRet

}

7.编译运行,可以看到整个地图的左下角,

要让它成为一个游戏,还需要三件事:玩家、玩家初始点、移动视图以便能够看到玩家。

8.Tiled支持两种类型层:tile层和对象层。对象层允许你在地图上可能发生事件的区域绘制矩形。比如:你可能需要一个怪物出生区域,或者一个一进入就会挂掉的区域。在这里,我们给玩家创建一个出生地。菜单栏→"图层"→"添加对象层",命名为"Objects",点击工具栏"插入对象",在地图上选择一个位置并点击它,这时会出现一个灰色的矩形框,右键选择"对象属性",名称填入"SpawnPoint",

按"确定"按钮。保存地图。

9.在HelloWorldScene.h文件中,添加如下声明:

1

CC_SYNTHESIZE_RETAIN(cocos2d::CCSprite*, _player, Player)

在HelloWorldScene.cpp构造函数中,添加如下:

1

_player = NULL

在init初始化函数,添加如下:

CCTMXObjectGroup *objects = _tileMap->objectGroupNamed("Objects")

CCAssert(objects != NULL, "Objects' object group not found")

CCDictionary *spawnPoint = objects->objectNamed("SpawnPoint")

CCAssert(spawnPoint != NULL, "SpawnPoint object not found")

int x = spawnPoint->valueForKey("x")->intValue()

int y = spawnPoint->valueForKey("y")->intValue()

this->setPlayer(CCSprite::create("Player.png"))

_player->setPosition(ccp(x, y))

this->addChild(_player)

this->setViewpointCenter(_player->getPosition())

添加一个方法setViewpointCenter,代码如下:

void HelloWorld::setViewpointCenter(CCPoint position)

{

CCSize winSize = CCDirector::sharedDirector()->getWinSize()

int x = MAX(position.x, winSize.width / 2)

int y = MAX(position.y, winSize.height / 2)

x = MIN(x, (_tileMap->getMapSize().width * _tileMap->getTileSize().width) - winSize.width / 2)

y = MIN(y, (_tileMap->getMapSize().height * _tileMap->getTileSize().height) - winSize.height / 2)

CCPoint actualPosition = ccp(x, y)

CCPoint centerOfView = ccp(winSize.width / 2, winSize.height / 2)

CCPoint viewPoint = ccpSub(centerOfView, actualPosition)

this->setPosition(viewPoint)

}

用户传任何的坐标过来,但是有一些点不希望显示出来,比如,我们不想屏幕移出地图边界,那里只是一片空白。如图:

摄像机的中心若是小于winSize.width/2或winSize.height/2,部分的视图将会在屏幕之外。同样的,我们需要检查边界条件。到目前为止,我们一直把这个函数看作是设置摄像机中心的位置。但是,这并不是我们实际做的。实际做的是移动整个层。看下图:

想象一下,身处在一个巨大的世界中,我们能看到的区域是从0到winSize.height/width的这部分。我们视野的中心是centerOfView,并且我们知道要让中心在哪儿(actualPosition)。所以要让我们视野的中心向上向右移动到actualPosition,我们只需要让地图相对的向下向左移动即可。这一步是通过actualPosition与centerOfView坐标相减得到的,然后把HelloWorld层的坐标设为这个结果。

10.编译运行,可以看到忍者在屏幕中,

11.接下来,让忍者可以移动。在HelloWorldScene.cpp文件init函数中,添加如下代码:

1

this->setTouchEnabled(true)

开启触摸,然后重载registerWithTouchDispatcher函数,代码如下:

void HelloWorld::registerWithTouchDispatcher(void)

{

CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true)

}

注册触摸事件,这样单点触摸ccTouchBegan和ccTouchEnded会被调用。重载ccTouchBegan函数,代码如下:

bool HelloWorld::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)

{

return true

}

返回true表明接受这个触摸。添加setPlayerPosition方法,来设置玩家坐标,代码如下:

void HelloWorld::setPlayerPosition(CCPoint position)

{

_player->setPosition(position)

}

重载ccTouchEnded方法,代码如下:

void HelloWorld::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)

{

CCPoint touchLocation = this->convertTouchToNodeSpace(pTouch)

CCPoint playerPos = _player->getPosition()

CCPoint diff = ccpSub(touchLocation, playerPos)

if (abs(diff.x) >abs(diff.y))

{

if (diff.x >0)

{

playerPos.x += _tileMap->getTileSize().width

}

else

{

playerPos.x -= _tileMap->getTileSize().width

}

}

else

{

if (diff.y >0)

{

playerPos.y += _tileMap->getTileSize().height

}

else

{

playerPos.y -= _tileMap->getTileSize().height

}

}

if (playerPos.x <= (_tileMap->getMapSize().width * _tileMap->getTileSize().width) &&

playerPos.y <= (_tileMap->getMapSize().height * _tileMap->getTileSize().height) &&

playerPos.y >= 0 &&playerPos.x >= 0)

{

setPlayerPosition(playerPos)

}

setViewpointCenter(_player->getPosition())

}

计算触摸点与玩家坐标之间的差值,来决定玩家的移动方向。

12.编译运行,点击屏幕,让忍者动起来,

美术层面上:

场景文件可视为一个屏幕,不能被嵌套到其他文件中。是游戏中必不可少的元素,可用来创建关卡、菜单等。

节点文件是界面的最基本元素,一般用来存储控件、及制作小动画,以便在其他类型文件中复用。

图层文件通常包含直接在屏幕上呈现的内容,我们需要在图层中加入精灵、文本标签或其他游戏元素,并设置这些元素的属性,如位置、方向和大小以及设置游戏元素的动作等。

技术层面上:

Cocos Framework的界面对象以树形式组织。

节点(Node)是构成树的基本元素,所有能够被挂载到树上的对象都必须继承节点,包括场景和图层对象。

场景(Scene)对象在Framework中一般作为一个界面的入口,即树的根。

图层(Layer),节点的扩展,能够监听游戏的触摸、重力感应、键盘事件。


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

原文地址: https://outofmemory.cn/bake/7955303.html

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

发表评论

登录后才能评论

评论列表(0条)

保存