问下如何实现Sprite移动到电脑屏幕页面超出边界边界

怎样解决CSS Sprite在高分屏(Retina)上显示模糊的问题? - 知乎1被浏览573分享邀请回答暂时还没有回答,开始写第一个回答怎样制作基于Cocos2d-x的SLG游戏-第2章(双指缩放,单指拖动的实现)
我们使用TiledMap制作了一张简单的地图,并把它加入到了程序中,紧接着本章将实现地图的双指缩放和单指移动功能。
是不是觉得这一功能很接地气,呵呵,其实在很多类似的大地图背景游戏中这是非常常见和必要的一项功能,玩家可以通过滑动屏幕实现地图的滚动预览,同时可以通过两个手指的拉伸和聚拢实现地图背景的放大缩小。下面,就跟着我们一起来实现吧。
双指缩放,单指拖动的实现
Cocos2d-x中有自己的一套事件分发机制,如果你还不是很清楚,可先阅读一文。
在Cocos2d-x 3.x 中,实现触摸响应的一般流程如下:
具体实现如下:
1、首先,在GameScene.h文件中声明成员函数。
onTouchesBegan(const
std::vector&cocos2d::Touch*&& touches, cocos2d::Event *event);
onTouchesMoved(const
std::vector&cocos2d::Touch*&& touches, cocos2d::Event *event);
2、在GameScene.cpp文件的init函数中创建并绑定触摸事件。
listener = EventListenerTouchAllAtOnce::create();
listener-&onTouchesBegan
= CC_CALLBACK_2(GameScene::onTouchesBegan, this);
listener-&onTouchesMoved
= CC_CALLBACK_2(GameScene::onTouchesMoved, this);
_eventDispatcher-&addEventListenerWithSceneGraphPriority(listener,
bgSprite);
3、最后在GameScene.cpp文件中实现触摸回调函数&
一旦玩家开始触碰屏幕,我们的程序就会开始调用相应的触摸事件处理函数来处理相应的逻辑,所以现在我们就可以来完成这部分的逻辑了。
实现中有以下几个需要注意的问题:
(上图中,背景图片的锚点在蓝点的位置,当我们想放大红圈所圈的那棵树时,如果只是简单的改变背景的放大倍率,那一定会出现上图的第二种情况(目标会向右上角偏移);但如果我们把背景的锚点和位置都设置到目标处,那就会像第三中情况一样,得到一个比较好的放大效果。)
掌握了这些注意事项以后,现在我们就可以开始具体的行动了。
首先,在GameScene.h中定义如下的变量:
bgSprite是地图背景,需要缩放和移动的对象都是其子节点,这样我们就可以通过操作它来实现缩放和移动了。bgOrigin用于记录bgSprite的初始原点位置。
接着,我们跳转到GameScene.cpp的init()方法,修改之前添加地图背景的方法,同时初始化bgOrigin。如下代码所示:
= Layer::create();
this-&addChild(mapLayer,-1);
= Sprite::create(&2.jpg&);
bgSprite-&setAnchorPoint(Vec2::ZERO);
bgSprite-&setPosition(Vec2::ZERO),
= Vec2(Vec2::ZERO);
mapLayer-&addChild(bgSprite);
treeSprite = Sprite::create(&1.png&);
treeSprite-&setAnchorPoint(Vec2::ZERO);
treeSprite-&setPosition(Vec2::ZERO),
treeSprite-&setScale(2);
bgSprite-&addChild(treeSprite,
map = TMXTiledMap::create(&mymap4.tmx&);
map-&setAnchorPoint(Vec2::ZERO);
map-&setPosition(Vec2::ZERO),
bgSprite-&addChild(map,
因为对层而言,它相比于其他的节点来说,其锚点、位置、大小都不好控制,所以我们需要通过另外的节点(比如这里的bgSprite)来执行后面的缩放和移动等动作。
最后压轴来了,实现触摸事件的处理函数如下:
GameScene::onTouchesMoved(const
std::vector&Touch*&& touches, Event& *event)
winSize = Director::getInstance()-&getWinSize();
&&&&if(touches.size()
& 1)&&&&&&&
&&&&&&&&auto
point1 = touches[0]-&getLocation();
&&&&&&&&auto
point2 = touches[1]-&getLocation();
&&&&&&&&auto
currDistance = point1.distance(point2);
&&&&&&&&auto
prevDistance = touches[0]-&getPreviousLocation().distance(touches[1]-&getPreviousLocation());
&&&&&&&&auto
pointVec1 = point1& - bgO
&&&&&&&&auto
pointVec2 = point2& - bgO
&&&&&&&&auto
relMidx = (pointVec1.x + pointVec2.x) / 2 ;
&&&&&&&&auto
relMidy = (pointVec1.y + pointVec2.y) / 2 ;
&&&&&&&&auto
anchorX = relMidx / bgSprite-&getBoundingBox().size.
&&&&&&&&auto
anchorY = relMidy / bgSprite-&getBoundingBox().size.
&&&&&&&&auto
absMidx = (point2.x + point1.x) / 2 ;
&&&&&&&&auto
absMidy = (point2.y + point1.y) / 2 ;
&&&&&&&&if(&
bgOrigin.x & 0)
&&&&&&&&&&&&absMidx
-= bgOrigin.x;
&&&&&&&&if(
bgOrigin.x & -bgSprite-&getBoundingBox().size.width + winSize.width )
&&&&&&&&&&&&absMidx
+=& -bgSprite-&getBoundingBox().size.width + winSize.width - bgOrigin.x;
&&&&&&&&if(
bgOrigin.y & 0 )
&&&&&&&&&&&&absMidy
-= bgOrigin.y;
&&&&&&&&if(
bgOrigin.y & -bgSprite-&getBoundingBox().size.height + winSize.height )
&&&&&&&&&&&&absMidy
+=& -bgSprite-&getBoundingBox().size.height + winSize.height - bgOrigin.y;
&&&&&&&&bgSprite-&setAnchorPoint(Vec2(anchorX,
anchorY));
&&&&&&&&bgSprite-&setPosition(Vec2(absMidx,
absMidy));
&&&&&&&&auto
scale = bgSprite-&getScale() * ( currDistance / prevDistance);
&&&&&&&&scale
= MIN(4,MAX(1, scale));
&&&&&&&&bgSprite-&setScale(scale);
&&&&&&&&bgOrigin
= Vec2(absMidx, absMidy) - Vec2(bgSprite-&getBoundingBox().size.width * anchorX, bgSprite-&getBoundingBox().size.height * anchorY) ;
if(touches.size()
== 1)&&&&&&&
&&&&&&&&auto
touch = touches[0];
&&&&&&&&auto
diff = touch-&getDelta();&&&&&&
&&&&&&&&auto
currentPos = bgSprite-&getPosition();
&&&&&&&&auto
pos = currentPos +
&&&&&&&&auto
bgSpriteCurrSize = bgSprite-&getBoundingBox().
&&&&&&&&pos.x
= MIN(pos.x, bgSpriteCurrSize.width * bgSprite-&getAnchorPoint().x);
&&&&&&&&pos.x
= MAX(pos.x, -bgSpriteCurrSize.width + winSize.width + bgSpriteCurrSize.width * bgSprite-&getAnchorPoint().x);
&&&&&&&&pos.y
= MIN(pos.y, bgSpriteCurrSize.height * bgSprite-&getAnchorPoint().y);
&&&&&&&&pos.y
= MAX(pos.y, -bgSpriteCurrSize.height + winSize.height + bgSpriteCurrSize.height * bgSprite-&getAnchorPoint().y);
&&&&&&&&bgSprite-&setPosition(pos);
&&&&&&&&if(
pos.x &= bgSpriteCurrSize.width * bgSprite-&getAnchorPoint().x
&&&&&&&&&&&||
pos.x &= -bgSpriteCurrSize.width + winSize.width + bgSpriteCurrSize.width * bgSprite-&getAnchorPoint().x)
&&&&&&&&&&&&diff.x
&&&&&&&&if(
pos.y &= bgSpriteCurrSize.height * bgSprite-&getAnchorPoint().y
&&&&&&&&&&&||
pos.y &= -bgSpriteCurrSize.height + winSize.height + bgSpriteCurrSize.height * bgSprite-&getAnchorPoint().y)
&&&&&&&&&&&&diff.y
&&&&&&&&bgOrigin
以上就是onTouchesMoved函数的实现方法了,原理已在注释中解释清楚,所以我想理解起来已经不会很难。下面给出一张示意图帮助大家理解:
下图是缩放过程中刚好出现空白的区域时的图形示意图:
此时空白的区域的宽等于&-bgSprite-&getBoundingBox().size.width + winSize.width - bgOrigin.x,所以我们把背景的位置向右移动-bgSprite-&getBoundingBox().size.width + winSize.width - bgOrigin.x个单位就可以避免这种情况的出现。
代码中有一点需要注意的是,在缩放过程中,bgSprite的尺寸不断变化的,所以计算起锚点或进行边界处理时,一定要用它缩放后的尺寸宽高来计算,而不能是它本身的宽高。 所以代码中计算bgSprite的尺寸我们用getBoundingBox函数来获得经过缩放和旋转之后的外框盒大小,而不用getContentSize函数来获得节点原始的大小。
iOS端多点触碰默认是关闭的,所以需要在AppController.mm 程序启动回调中启用多点触摸才可以,具体方法是在以下的函数段后加入[eaglView setMultipleTouchEnabled:YES];
如下所示:
CCEAGLView
*eaglView = [CCEAGLView viewWithFrame: [window bounds]
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&pixelFormat:
kEAGLColorFormatRGBA8
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&depthFormat:
GL_DEPTH24_STENCIL8_OES
&&&&&&&&&&&&&&&&&&&&&&&&&&preserveBackbuffer:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&sharegroup:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&multiSampling:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&numberOfSamples:
[eaglView&
setMultipleTouchEnabled:YES];
总的来说,要想很好的实现这一功能不是容易的,以上就是我们实现了的一种方法,虽然细节上还有一些问题,也未在真机上测试,但还是希望能对大家的学习有所帮助。如果你有更好的方法实现,也可以提出来,大家一起进步学习。
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!豆丁微信公众号
君,已阅读到文档的结尾了呢~~
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
Cocos2d开发系列(七)
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='http://www.docin.com/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口查看: 1097|回复: 4
问下如何实现Sprite移动到屏幕边界时,从另一边出现
主题帖子贡献
初级UU族—3级, 积分 295, 距离下一级还需 205 积分
初级UU族—3级, 积分 295, 距离下一级还需 205 积分
07:58:04 |
Sprite移动到屏幕边界时,会穿过屏幕边界,从另一边出现。就像一直在屏幕范围中运动一样,各位大神给个思路。
1.png (17.01 KB, 下载次数: 0)
07:57 上传
主题帖子贡献
初级UU族—3级, 积分 385, 距离下一级还需 115 积分
初级UU族—3级, 积分 385, 距离下一级还需 115 积分
01:51:44 |
分别在上下左右再加一个camera, 把camera的视角投射方式设置为 Orthographic,把清除方式设置为Depth Only
主题帖子贡献
初级UU族—3级, 积分 295, 距离下一级还需 205 积分
初级UU族—3级, 积分 295, 距离下一级还需 205 积分
&楼主| 发表于
11:35:59 |
分别在上下左右再加一个camera, 把camera的视角投射方式设置为 Orthographic,把清除方式设置为Depth Only ... 你好,能说的再具体一点吗,不是很理解。
主题帖子贡献
初级UU族—3级, 积分 385, 距离下一级还需 115 积分
初级UU族—3级, 积分 385, 距离下一级还需 115 积分
02:04:47 |
)WG8WJ74SH)Z20%@YC`T)0U.png (228.35 KB, 下载次数: 0)
02:02 上传
大概是上图这样, Camera设置成只能看到Player,在Player完全走出上一个摄像机之后,把Player的位置再恢复到中间的Camera,
我突然觉得这种方法不算特别好,我不是做2D游戏的,你参考一下就好了。。
主题帖子贡献
初级UU族—1级, 积分 35, 距离下一级还需 15 积分
初级UU族—1级, 积分 35, 距离下一级还需 15 积分
16:16:48 |
在地图外设置一个子物体,位置随着母物体的位置变化
浏览过的版块
(function() { var viewsource = []; var copycode = []; if(document.getElementsByClassName) { viewsource = document.getElementsByClassName('viewsource'); copycode = document.getElementsByClassName('copycode'); } else { var emlist = document.getElementsByTagName('em'); for(var i=0;i<emlist.i++) { if(emlist[i].className == 'viewsource') { vie通过向量概念控制Sprite的移动实践 - 简书
通过向量概念控制Sprite的移动实践
定义类变量
//Sprite僵尸主角
let zombie = SKSpriteNode(imageNamed: "zombie1")
//上一帧更新的时间,用于跟currentTime比对
var lastUpdateTime : TimeInterval = 0
//相邻两帧的时间差,dt = currentTime - lastUpdateTime
var dt : TimeInterval = 0
//僵尸每秒钟的移动点数
let zombieMovePointsPerSec:CGFloat = 480.0
//移动向量
var velocity = CGPoint.zero
//最后点击的位置
var lastTouchLocation = CGPoint.zero
初始化场景 - 固定套路
override func viewDidLoad() {
super.viewDidLoad()
//Initialize scene
let scene = GameScene(size: CGSize(width: 1920, height: 1080))
//Initialize skView
let skView = self.view as! SKView
//Set FPS & node count present in the scene
skView.showsFPS = true
skView.showsNodeCount = true
//A Boolean value that indicates whether parent-child and sibling relationships affect the rendering order of nodes in the scene.
skView.ignoresSiblingOrder = true
//Set the scaleMode
scene.scaleMode = .aspectFill
//Present scene in skView
skView.presentScene(scene)
初始化bg并添加到场景中、设置僵尸的初始位置并添加到场景中
override func didMove(to view: SKView) {
//初始化bg并添加到场景中
let bg = SKSpriteNode(imageNamed: "background1")
bg.scale(to: CGSize(width: 1920, height: 1080))
bg.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
bg.zPosition = -1
addChild(bg)
//设置僵尸初始位置并添加到场景中
zombie.position = CGPoint(x: size.width/4, y: size.height/4)
addChild(zombie)
通过touchesBegan或touchesMoved确定最后点击的位置
5.在触摸事件中调用moveZombieForward(location: touchLocation)
override func touchesBegan(_ touches: Set&UITouch&, with event: UIEvent?) {
guard let touch
= touches.first else {
let touchLocation = touch.location(in: self)
lastTouchLocation = touchLocation
moveZombieForward(location: touchLocation)
override func touchesMoved(_ touches: Set&UITouch&, with event: UIEvent?) {
guard let touch = touches.first else {
let touchLocation = touch.location(in: self)
lastTouchLocation = touchLocation
moveZombieForward(location: touchLocation)
6.设置僵尸移动的向量、运动直线距离、方向以及速度
func moveZombieForward(location:CGPoint) {
//触摸点与当前僵尸位置的偏移量
let offset = CGPoint(x: location.x - zombie.position.x, y: location.y - zombie.position.y)
//根据偏移量算触摸点与当前僵尸位置的直线距离
let length = sqrt(Double(offset.x * offset.x + offset.y * offset.y))
//根据偏移量及直线距离,算出从当前僵尸的位置到触摸点方向的向量,其实Y/X就是直线的斜率
let direction = CGPoint(x: offset.x/CGFloat(length), y: offset.y/CGFloat(length))
//速度的表达式,高中物理学过,速度和速率是有区别的,速度不仅仅表现物体运动的快慢,还表现了物体运动的方向。而速率只表现了物体运动的快慢
velocity = CGPoint(x: direction.x * zombieMovePointsPerSec, y: direction.y * zombieMovePointsPerSec)
得到了僵尸运动的速度,现在就可以写僵尸移动的方法,然后在update()函数中去调用。
注:dt = currentTime - lastUpdateTime 也就是两帧之间的时间差。将dt * velocity 就是每一帧僵尸实际运动的距离
func move(sprite:SKSpriteNode, velocity:CGPoint) {
let amountToMove = CGPoint(x: velocity.x * CGFloat(dt), y: velocity.y * CGFloat(dt))
sprite.position = CGPoint(x: sprite.position.x + amountToMove.x, y: sprite.position.y + amountToMove.y)
8.这里还有一个rotate方法,是在每次点击屏幕后,僵尸都会旋转到正朝点击位置的方向。这里我就没有按照教程直接设置zombie.zRotation了,而是直接使用了SKAction.rotate的方法,这样能让僵尸转向得更自然一些,没那么生硬。
三角函数就不同说了吧,Y/X一般都是等于斜率角度的正切值,使用atan2(Double,Double)反正切函数,计算出旋转角度,僵尸就乖乖地旋转过去啦。
func rotate(sprite:SKSpriteNode, direction:CGPoint){
sprite.zRotation = CGFloat(atan2(direction.y, direction.x))
sprite.run(SKAction.rotate(toAngle: CGFloat(atan2(direction.y, direction.x)), duration: 0.2))
然后就是能让僵尸相应点击事件的update函数了,其实学了下一章SKAction,就不必依赖update函数来执行移动操作了,因为这样我感觉效率会很低,而且sprite不容易控制。但是还是先按照教程这样写吧?
override func update(_ currentTime: TimeInterval) {
//计算相邻两帧的时间差
if lastUpdateTime & 0 {
dt = currentTime - lastUpdateTime
//然后将当前时间赋值到上次更新的时间,周而复始
lastUpdateTime = currentTime
//根据不断变化的速度velocity将移动事件作用到zombie这个sprite上,让他进行移动。
move(sprite: zombie, velocity: velocity)
//该旋转时就旋转
rotate(sprite: zombie, direction: velocity)
//边界碰撞检测
boundsCheckZombie()
//僵尸距离点击的点还有6个点时就停止
if abs(zombie.position.x - lastTouchLocation.x) &= 6 || abs(zombie.position.y - lastTouchLocation.y) &= 6 {
zombie.position = lastTouchLocation
velocity = CGPoint.zero
10.到这里,僵尸就已经可以乖乖的听你话,指哪走哪了,但是我们还是不希望僵尸出边框对吧?因为还没学到物理引擎检测碰撞那里,我们还是用几何知识来解决这个问题,检测sprite到边界的距离,如果越界了,首先让sprite的位置回到边界的位置,然后让其朝反方向移动,也就相当于弹回来了。
let bottomLeft = CGPoint.zero
let topRight = CGPoint(x: size.width, y: size.height)
if zombie.position.x - zombie.size.width/2 &= bottomLeft.x {
zombie.position.x = bottomLeft.x + zombie.size.width/2
velocity.x = -velocity.x
if zombie.position.x + zombie.size.width/2 &= topRight.x {
zombie.position.x = topRight.x - zombie.size.width/2
velocity.x = -velocity.x
if zombie.position.y - zombie.size.height/2 &= bottomLeft.y {
zombie.position.y = bottomLeft.y + zombie.size.height/2
velocity.y = -velocity.y
if zombie.position.y + zombie.size.height/2 &= topRight.y {
zombie.position.y = topRight.y - zombie.size.height/2
velocity.y = -velocity.y
好了,第一章已经学完了,下周开始学第二章SKAction。
To be continued...

我要回帖

更多关于 无尽的边界移动网络 的文章

 

随机推荐