游戏中主角根据触摸点来旋转对应的角度

本文详细介绍了如何在Cocos2d-x中通过触屏操作使游戏角色进行旋转的方法。利用坐标计算和atan2函数求取旋转角度,实现了角色朝向触摸点的动态效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在游戏中..经常要用到触摸屏幕 来让我们的 主角移动.旋转.那这些效果是如何做出来的? 

   下面有火爷给大家详细介绍

   首先,我们来看一幅图


  
 
这是我们看到人物与触摸点的位置。 那么我们如何求得人物与触摸点的角度?

我们在来看第二张图
 那么在游戏中。。  人物坐标与触摸点坐标是已知的。。  就可以计算出 a,b两条边
a=触摸点坐标y-人物坐标y
b= 
触摸点坐标x-人物坐标x

得出ab两边的值,那么我们就要求第三边的斜率
设k为斜率
k=a/b;
那么拿到了 斜率。。我们就可以求方位角了。
rotate=arctan(k); 这样我们就拿到了角度了。。

那么在cocos2d-x中如何来运用?

首先创建一个精灵

auto sp=Sprite::create("1.png");
sp->setPoint(100,200);
this->addChild(sp,1,2);
//创建触摸监听
auto listener=EventListenerTouchOneByOne::create();
listener->onTouchBegan=[&](Touch * touch ,Event *event)->bool{
   //第一步获取触摸点坐标
    Point p=touch->getLocation();
    //获取人物
    auto sp=this->getChildByTag(2);
    double rotate=std::atan2((p.y-sp->getPositionY()),(p,x- sp->getPositionX()))*180/3.1416926
    //人物旋转角度
    sp->runAction(RotateTo::create(0.3.rotate));
    return true;
};
//注册触摸
 
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener,this);

代码结束
=======================================================================================
 大家可以做一辆可旋转炮塔的坦克了。。 那些 捕鱼哒人 旋转炮塔也就是这样做出来的。到此结束。
                                                                                                                                                
import { _decorator, Component, Node, director, resources, instantiate, Vec3, math } from 'cc'; import { GameData } from './GameData'; import { A_guagouyidong } from './A_guagouyidong'; import { B_pengzhuangDefenxitong } from './B_pengzhuangDefenxitong'; import { ditu } from './C_ditu'; import { A_HUAHUAweizhi } from './A_HUAHUAweizhi'; import { zizhuandaishangwawa2 } from './zizhuandaishangwawa2'; import { fuhuoUI } from './fuhuoUI'; import { GameOverUI } from './GameOverUI'; const { ccclass, property } = _decorator; @ccclass('AA_GameManager') export class GameManager extends Component { @property(Node) clawNode: Node = null; // 爪子节 @property(Node) collisionSystemNode: Node = null; // 碰撞系统节 @property(Node) mapNode: Node = null; // 地图节 @property(Node) flowerSpawnerNode: Node = null; // 花朵生成器节 @property(Node) rotationComponentNode: Node = null; // 旋转组件节 @property(Node) cameraFollowNode: Node = null; // 相机跟随节 @property(Node) reviveUINode: Node = null; // 复活UI节 @property(Node) gameOverUINode: Node = null; // 游戏结束UI节 public isGameActive: boolean = false; private currentLevel: number = 1; onLoad() { this.initializeGame(); } /** * 初始化游戏 */ private initializeGame() { // 重置游戏数据 GameData.reset(); // 获取或初始化组件 if (!this.clawNode) this.clawNode = this.node.getChildByName('Claw'); if (!this.collisionSystemNode) this.collisionSystemNode = this.node.getChildByName('CollisionSystem'); if (!this.mapNode) this.mapNode = this.node.getChildByName('Map'); if (!this.flowerSpawnerNode) this.flowerSpawnerNode = this.node.getChildByName('FlowerSpawner'); if (!this.rotationComponentNode) this.rotationComponentNode = this.node.getChildByName('RotationComponent'); if (!this.cameraFollowNode) this.cameraFollowNode = this.node.getChildByName('CameraFollow'); if (!this.reviveUINode) this.reviveUINode = this.node.getChildByName('ReviveUI'); if (!this.gameOverUINode) this.gameOverUINode = this.node.getChildByName('GameOverUI'); // 初始化游戏状态 this.isGameActive = true; } /** * 开始游戏 */ public startGame() { if (!this.isGameActive) { // 重置所有游戏组件 this.resetGameComponents(); // 初始化UI this.resetUI(); // 设置游戏状态 this.isGameActive = true; this.currentLevel = 1; // 开始游戏循环 this.scheduleOnce(() => { this.enableGameComponents(true); }, 0.1); } } /** * 重置UI状态 */ private resetUI() { if (this.reviveUINode?.isValid) { const reviveUI = this.reviveUINode.getComponent(fuhuoUI); if (reviveUI) reviveUI.hide(); } if (this.gameOverUINode?.isValid) { const gameOverUI = this.gameOverUINode.getComponent(GameOverUI); if (gameOverUI) gameOverUI.hide(); } } /** * 重置游戏 */ public resetGame() { // 1. 停止所有游戏活动 this.isGameActive = false; this.enableGameComponents(false); // 2. 重置游戏数据 GameData.reset(); // 3. 重置所有UI状态 this.resetUI(); // 4. 重置游戏组件 this.resetGameComponents(); // 5. 延迟开始游戏确保完全重置 this.scheduleOnce(() => { this.startGame(); }, 0.3); // 增加延迟时间确保完全重置 } /** * 重置游戏组件 */ private resetGameComponents() { // 重置爪子 if (this.clawNode?.isValid) { const clawMovement = this.clawNode.getComponent(A_guagouyidong); if (clawMovement) { if (clawMovement.resetPosition) { clawMovement.resetPosition(); } else { clawMovement.stopMovement(); // clawMovement.isFirstClick = true; } } } // 确保设置碰撞系统的回调 if (this.collisionSystemNode?.isValid) { const collisionSystem = this.collisionSystemNode.getComponent(B_pengzhuangDefenxitong); if (collisionSystem) { collisionSystem.setGameOverCallback(this.gameOver.bind(this)); // 确保UI引用正确 collisionSystem.GameOverUI = this.gameOverUINode?.getComponent(GameOverUI); } } // 重置碰撞系统 if (this.collisionSystemNode?.isValid) { const collisionSystem = this.collisionSystemNode.getComponent(B_pengzhuangDefenxitong); if (collisionSystem) { collisionSystem.reset(); // 新增 collisionSystem.setGameOverCallback(this.gameOver.bind(this)); // 每次都设置 collisionSystem.GameOverUI = this.gameOverUINode?.getComponent(GameOverUI); // 每次都设置 //collisionSystem.stopAllMovements(); } } // 重置地图 if (this.mapNode?.isValid) { const mapComponent = this.mapNode.getComponent(ditu); if (mapComponent) { mapComponent.generateMap(); } } // 重置花朵生成器 if (this.flowerSpawnerNode?.isValid) { const flowerSpawner = this.flowerSpawnerNode.getComponent(A_HUAHUAweizhi); if (flowerSpawner) { flowerSpawner.showFlowers(); } } // 重置旋转组件 if (this.rotationComponentNode?.isValid) { const rotationComponent = this.rotationComponentNode.getComponent(zizhuandaishangwawa2); if (rotationComponent) { rotationComponent.enabled = true; } } } /** * 启用或禁用游戏组件 * @param enable 是否启用 */ private enableGameComponents(enable: boolean) { // 启用/禁用爪子移动 if (this.clawNode?.isValid) { const clawMovement = this.clawNode.getComponent(A_guagouyidong); if (clawMovement) { if (enable) { clawMovement.resumeMovement(); } else { clawMovement.stopMovement(); } } } // 启用/禁用旋转组件 if (this.rotationComponentNode?.isValid) { const rotationComponent = this.rotationComponentNode.getComponent(zizhuandaishangwawa2); if (rotationComponent) { rotationComponent.enabled = enable; } } // 启用/禁用碰撞系统 if (this.collisionSystemNode?.isValid) { const collisionSystem = this.collisionSystemNode.getComponent(B_pengzhuangDefenxitong); if (collisionSystem) { // 碰撞系统本身会根据游戏状态处理 } } } /** * 游戏结束 * @param isSuccess 是否成功 */ public gameOver(isSuccess: boolean) { // 确保只处理一次 if (!this.isGameActive) return; this.isGameActive = false; this.enableGameComponents(false); // 延迟显示确保UI更新 this.scheduleOnce(() => { if (this.gameOverUINode?.isValid) { const gameOverUI = this.gameOverUINode.getComponent(GameOverUI); if (gameOverUI) { gameOverUI.show(GameData.getScore()); } } }, 0.1); } /** * 返回主页 */ public goToHome() { this.unscheduleAllCallbacks(); director.loadScene('HomeScene'); } /** * 下一关 */ public nextLevel() { this.currentLevel++; this.resetGame(); } /** * 暂停游戏 */ public pauseGame() { if (this.isGameActive) { this.isGameActive = false; this.enableGameComponents(false); } } /** * 恢复游戏 */ public resumeGame() { if (!this.isGameActive) { this.isGameActive = true; this.enableGameComponents(true); } } } 。import { _decorator, Button, Component, misc, Node } from 'cc'; import { GameData } from './GameData'; import { GameManager } from './AA_GameManager'; import { zizhuandaishangwawa2 } from './zizhuandaishangwawa2'; const { ccclass, property } = _decorator; @ccclass('chongwananniu') export class chongwananniu extends Component { @property(GameManager) gameManager: GameManager = null; @property(Node) rotationComponentNode: Node = null; // 旋转组件节(娃娃出现系统) private isEventBound = false; private currentWawaData: {x: number, y: number, angle: number}[] = []; // 保存娃娃位置和角度数据 onLoad() { this.node.on(Button.EventType.CLICK, this.onReplayClick, this); this.isEventBound = true; } private onReplayClick() { // 简单直接调用游戏管理器重置 if (this.gameManager && this.gameManager.node?.isValid) { this.gameManager.resetGame(); } } private saveCurrentWawas() { if (this.rotationComponentNode) { const wawaComponent = this.rotationComponentNode.getComponent(zizhuandaishangwawa2); if (wawaComponent) { this.currentWawaData = []; for (const child of wawaComponent.children) { if (child && child.isValid) { const pos = child.position; this.currentWawaData.push({ x: pos.x, y: pos.y, angle: child.angle }); } } } } } private restoreWawas() { if (this.rotationComponentNode && this.currentWawaData.length > 0) { const wawaComponent = this.rotationComponentNode.getComponent(zizhuandaishangwawa2); if (wawaComponent) { // 确保有足够的娃娃节 if (wawaComponent.children.length < this.currentWawaData.length) { console.warn("Not enough wawa nodes to restore"); return; } // 恢复位置和角度 for (let i = 0; i < this.currentWawaData.length; i++) { if (i < wawaComponent.children.length && wawaComponent.children[i] && wawaComponent.children[i].isValid) { const child = wawaComponent.children[i]; const data = this.currentWawaData[i]; child.setPosition(data.x, data.y); child.angle = data.angle; child.active = true; } } // 确保组件启用 wawaComponent.enabled = true; } } } onDestroy() { if (this.isEventBound) { this.node.off(Button.EventType.CLICK, this.onReplayClick, this); } } } 。import { _decorator, Component, EventTouch, Input, input, Vec2, Vec3 } from 'cc'; const { ccclass, property } = _decorator; @ccclass('A_guagouyidong') export class A_guagouyidong extends Component { private isGameActive: boolean = true; public isFirstClick: boolean = true; // 是否第一次击 private direction: Vec2 = new Vec2(0, -1); // 初始方向 -Y private initialPosition: Vec3 = new Vec3();//初始位置 @property private speed: number = 20; // 移动速度 private angle: number = -90; // 当前角度 (-90度代表-y方向) private currentAngle: number = -90; // 初始角度-90 度 onLoad() { // 保存初始位置 this.initialPosition = this.node.position.clone(); // 只在游戏活跃时监听触摸事件 //if (this.isGameActive) { // 监听触摸事件 input.on(Input.EventType.TOUCH_START, this.onTouchStart, this); //} } /** * 重置爪子位置到初始位置 */ public resetPosition() { // 确保节有效 if (!this.node || !this.node.isValid) return; // 重置位置 this.node.position = this.initialPosition.clone(); //this.stopMovement(); this.isFirstClick = true; this.direction = new Vec2(0, -1); // 重置方向为 -Y this.angle = 0; // 重置角度 this.currentAngle = 0; // 重置当前角度 // 重置旋转 this.node.setRotationFromEuler(0, 0, this.currentAngle); // 重新激活移动 this.isGameActive = true; } stopMovement() { this.isGameActive = false; // 设置游戏状态为结束 this.isFirstClick = true; // 重置击状态(防止继续移动) //input.off(Input.EventType.TOUCH_START, this.onTouchStart, this); // 移除触摸监听 } // 在 A_guagouyidong-001.ts 中添加 resumeMovement() { this.isGameActive = true; //input.off(Input.EventType.TOUCH_START, this.onTouchStart, this); // 先解绑 //this.isFirstClick = true; // 重置击状态 //input.on(Input.EventType.TOUCH_START, this.onTouchStart, this); // 重新绑定 } onTouchStart(event: EventTouch) { if (!this.isGameActive) return; // 游戏结束时不再响应 if (this.isFirstClick) { // 第一次击,开始向 -Y 方向移动 this.isFirstClick = false; this.moveInDirection(this.direction); } else { this.toggleDirection(); // 调用切换方向的方法 } } toggleDirection() { this.angle = (this.angle === -135) ? -45 : -135; this.direction = new Vec2(Math.cos(this.angle * (Math.PI / 180)), Math.sin(this.angle * (Math.PI / 180))); this.moveInDirection(this.direction); // 切换当前角度 this.currentAngle = (this.currentAngle === 315) ? 45 : 315; this.node.setRotationFromEuler(0, 0, this.currentAngle); } moveInDirection(direction: Vec2) { // 获取当前节的位置 const currentPosition = this.node.position; // 更新节位置 const newPosition = new Vec3( currentPosition.x + direction.x * this.speed * 0.02, currentPosition.y + direction.y * this.speed * 0.02, currentPosition.z); this.node.setPosition(newPosition); } update(deltaTime: number) { if (!this.isGameActive) return; // 游戏结束时不再移动 // 如果不是第一次击,持续移动 if (!this.isFirstClick) { this.moveInDirection(this.direction); } } onDestroy() { // 移除事件监听 input.off(Input.EventType.TOUCH_START, this.onTouchStart, this); } }。import { _decorator, Collider2D, Component, Contact2DType, Label, Node, isValid, Camera, UITransform, Vec3, view} from 'cc'; import { GameOverUI } from './GameOverUI'; import { GameData } from './GameData'; import { Tags } from './Tags'; import { A_guagouyidong } from './A_guagouyidong'; import { fuhuoUI } from './fuhuoUI'; const { ccclass, property } = _decorator; @ccclass('B_pengzhuangDefenxitong') export class B_pengzhuangDefenxitong extends Component { // 使用单个Map替代多个Set private processedColliders: Map<string, Tags> = new Map(); @property(fuhuoUI) fuhuoUI: fuhuoUI = null; @property(GameOverUI) GameOverUI: GameOverUI = null; @property(Node) zizhuandaishangwawa2: Node = null; @property(Camera) mainCamera: Camera = null; @property(Label) chanceLabel: Label = null; // 游戏结束回调函数 private onGameOverCallback: (isSuccess: boolean) => void = null; onLoad() { // 碰撞检测 const collider = this.getComponent(Collider2D); if (collider) { collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); collider.on(Contact2DType.END_CONTACT, this.onEndContact, this); } // 更新机会显示 this.updateChanceUI(); } /** * 设置游戏结束回调 * @param callback 回调函数 */ public setGameOverCallback(callback: (isSuccess: boolean) => void) { this.onGameOverCallback = callback; } onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D) { const colliderId = otherCollider.uuid; // 如果已处理过该碰撞体,直接返回 if (this.processedColliders.has(colliderId)) return; switch (otherCollider.tag) { case Tags.HUAHUA: this.processedColliders.set(colliderId, Tags.HUAHUA); this.addScore(1); // 延迟销毁花朵 this.scheduleOnce(() => { if (isValid(otherCollider.node)) { otherCollider.node.destroy(); } }, 0.001); break; case Tags.WAWA: this.processedColliders.set(colliderId, Tags.WAWA); this.addScore(10); // 统一通过回调处理游戏结束 if (this.onGameOverCallback) { this.onGameOverCallback(true); } else { // 如果没有设置回调,使用本地方法 this.gameOver(true); } break; case Tags.DITU: this.processedColliders.set(colliderId, Tags.DITU); GameData.loseChance(); this.updateChanceUI(); // 检查是否需要显示复活界面 if (GameData.shouldShowRevive()) { this.stopAllMovements(); // 延迟显示复活界面 this.scheduleOnce(() => { if (this.fuhuoUI && isValid(this.fuhuoUI.node)) { this.fuhuoUI.show(); } }, 0.2); } break; } } onEndContact(selfCollider: Collider2D, otherCollider: Collider2D) { const colliderId = otherCollider.uuid; // 只移除地图碰撞记录 if (otherCollider.tag === Tags.DITU && this.processedColliders.has(colliderId)) { this.processedColliders.delete(colliderId); } } updateChanceUI() { if (this.chanceLabel && isValid(this.chanceLabel.node)) { this.chanceLabel.string = GameData.getChances().toString(); } } public stopAllMovements() { // 停止爪子移动 if (this.node?.isValid) { const moveComp = this.node.getComponent(A_guagouyidong); if (moveComp) { moveComp.stopMovement(); } } // 停止旋转组件 if (this.zizhuandaishangwawa2?.isValid) { const component = this.zizhuandaishangwawa2.getComponent("zizhuandaishangwawa2"); if (component) { component.enabled = false; } } } public gameOver(isSuccess: boolean) { // 调用停止移动的方法 if (this.node?.isValid) { const moveComp = this.node.getComponent(A_guagouyidong); if (moveComp) { moveComp.stopMovement(); } } // 停止旋转组件 if (this.zizhuandaishangwawa2?.isValid) { const component = this.zizhuandaishangwawa2.getComponent("zizhuandaishangwawa2"); if (component) { component.enabled = false; } } // 显示游戏结束界面 if (this.GameOverUI?.isValid) { const cameraWorldPos = this.mainCamera.node.worldPosition; this.GameOverUI.node.setWorldPosition(cameraWorldPos); this.GameOverUI.show(GameData.getScore()); } } public reset() { this.processedColliders.clear(); this.updateChanceUI(); } private addScore(count: number = 1) { GameData.addScore(count); } } 。脚本都没问题了,还有个小bug,就是游戏在重玩之后,重玩几回之后,主角依然会出现击两次才正常移动的情况。大概重玩三四回,有一回会这样,然后有正常了,然后有几回后又出现。就是第一次击会动一下然后停止了,然后再第二次就正常移动正常游戏了。/** * 重置爪子位置到初始位置 */ public resetPosition() { // 确保节有效 if (!this.node || !this.node.isValid) return; // 重置位置 this.node.position = this.initialPosition.clone(); //this.stopMovement(); this.isFirstClick = true; this.direction = new Vec2(0, -1); // 重置方向为 -Y this.angle = 0; // 重置角度 this.currentAngle = 0; // 重置当前角度 // 重置旋转 this.node.setRotationFromEuler(0, 0, this.currentAngle); // 重新激活移动 this.isGameActive = true; } stopMovement() { this.isGameActive = false; // 设置游戏状态为结束 this.isFirstClick = true; // 重置击状态(防止继续移动) //input.off(Input.EventType.TOUCH_START, this.onTouchStart, this); // 移除触摸监听 } // 在 A_guagouyidong-001.ts 中添加 resumeMovement() { this.isGameActive = true; //input.off(Input.EventType.TOUCH_START, this.onTouchStart, this); // 先解绑 //this.isFirstClick = true; // 重置击状态 //input.on(Input.EventType.TOUCH_START, this.onTouchStart, this); // 重新绑定 }我猜测问题出在这里, stopMovement() { this.isGameActive = false; // 设置游戏状态为结束 this.isFirstClick = true; // 重置击状态(防止继续移动)这里不能改,游戏中途需要的。请看需要怎样修改,使用游戏重玩杜绝以上bug
最新发布
06-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值