敌人角色和子弹射击之间的碰撞 - (Cocos2dx, C++, Android)
Collision between enemy characters and bullets shot - (Cocos2dx, C++, Android)
我的问题是我为敌人角色对象和子弹对象编写的碰撞检测。
符号:
当我用子弹射击 1 个敌方角色时,敌方角色会正常被摧毁。
但是,如果生成了 2 个或更多敌人角色并且我射击了第一个生成的敌人,它什么都不做。
最后一个被生成和射击的角色被毫无问题地摧毁。
我是如何修复它的:
我决定通过创建一个 int 变量给每个敌人角色一个唯一的 ID,并在每次生成敌人时随机化它。
这确保我每个敌人角色对象肯定会有一个唯一的标识符,这样如果我射击他们,我可以以某种方式将那个唯一的 ID 与我的子弹相匹配。
但是,我不知道如何解决这个问题。下面的代码只是删除与任何随机标签相关联的每个敌人角色
我的问题:
我如何设置我的子弹对象来保存我的敌人角色的每个唯一 ID,以便当子弹击中一个(无论具体顺序如何)时它会搜索然后将它具有的唯一 ID 与已击中敌方角色ID?
如果我的问题不清楚或者我的编码风格很糟糕,我们深表歉意。
GameScene.cpp
/**
* @param ENEMY_SPAWN_FREQUENCY value is 0.002, set to make them spawn automatically every few seconds
*/
void GameScene::updateScheduler() {
this -> scheduleUpdate();
this -> schedule(schedule_selector(GameScene::spawnEnemyCharacter), ENEMY_SPAWN_FREQUENCY * visibleSize.width);
}
// ...
bool GameScene::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event) {
// fire button
auto target = (Sprite*)this -> getChildByTag(FIRE_BUTTON_TAG);
Rect rect = target -> getBoundingBox();
Point p = touch -> getLocation();
// initialize bullets
if (rect.containsPoint(p)) {
GameScene::spawnBullets(PLAYER_TAG, playerCharacter->getPositionX(), playerCharacter->getPositionY()+100, 0, REFERENCE_SIZE_Y);
return true;
}
// ...
return false;
}
// ... somewhere below my GameScene.cpp class
void GameScene::spawnBullets(int shooter_id, int x, int y, int p_x, int p_y) {
// load bullet sprites.
SpriteFrameCache::getInstance() -> addSpriteFramesWithFile("bullets.plist");
// ...
auto bulletBody = PhysicsBody::createBox(bullet_sprite -> getContentSize());
bulletBody -> setDynamic(true);
bulletBody -> setGravityEnable(false);
bulletBody -> setCollisionBitmask(BULLET_COLLISION_BITMASK);
bulletBody -> setContactTestBitmask(true);
bullet_sprite -> setPhysicsBody(bulletBody);
bullet_sprite -> setPosition(Point( x, y));
bullet_sprite -> setScale(0.2f);
bullet_sprite -> setTag(BULLET_TAG);
this -> addChild(bullet_sprite);
// animate bullet object so that it shoots
bullet_obj.fireBullet(bullet_sprite, p_x, p_y);
}
// ... somewhere further down this class i define my enemy characters to be spawned as enemy objects in the below method
void GameScene::spawnEnemyCharacter(float dt) {
int random_tag = rand(); // ensure that each enemy character object has a unique random id as its tag
enemyCharacter_obj.spawnEnemy(this, random_tag);
enemy_tags.push_back(random_tag);
// ... destroy enemy characters if hit by bullet:
bool GameScene::onContactBegin( cocos2d::PhysicsContact &contact ) {
PhysicsBody *a = contact.getShapeA() -> getBody();
PhysicsBody *b = contact.getShapeB() -> getBody();
if (BULLET_COLLISION_BITMASK == a->getCollisionBitmask() && ENEMY_COLLISION_BITMASK == b-> getCollisionBitmask() ||
BULLET_COLLISION_BITMASK == b->getCollisionBitmask() && ENEMY_COLLISION_BITMASK == a-> getCollisionBitmask() ) {
// delete enemys with random tag
for (std::vector<int>::iterator itl = enemy_tags.begin(); itl != enemy_tags.end(); ++itl) {
enemyCharacter_obj.destroyEnemyCharacter(this, *itl);
}
this -> removeChild(bullet_sprite);
}
return true;
}
Bullet.cpp
void Bullet::fireBullet(Sprite* bullet_sprite, int x, int y) {
auto bulletAction = Sequence::create( MoveBy::create(BULLETSPEED, Point(x, y)), CallFuncN::create( CC_CALLBACK_1(Bullet::doRemoveFromParentAndCleanup, this, true)), NULL);
bullet_sprite -> runAction(bulletAction);
}
现在我的敌人角色class:
void EnemyCharacter::spawnEnemy(cocos2d::Layer* layer, int random_tag) {
// データ読み込み
SpriteFrameCache::getInstance() -> addSpriteFramesWithFile("enemies.plist");
// 敵キャラクター
enemyCharacter = Sprite::createWithSpriteFrameName("enemy_1.png");
auto enemyCharacterBody = PhysicsBody::createBox(enemyCharacter -> getContentSize() / 5);
// ...
auto enemyCharacterPosition = (random * visibleSize.height ) + ( enemyCharacter -> getContentSize().height / 2);
enemyCharacterBody -> setDynamic(false);
enemyCharacterBody -> setCollisionBitmask(ENEMY_COLLISION_BITMASK);
enemyCharacterBody -> setContactTestBitmask(true);
enemyCharacter -> setScale(0.3f);
enemyCharacter -> setTag(random_tag);
enemyCharacter -> setPhysicsBody(enemyCharacterBody);
enemyCharacter -> setPosition( Point( ((random * visibleSize.width) + (enemyCharacter->getContentSize().width / 2)), visibleSize.height ) );
layer -> addChild(enemyCharacter);
// ...
}
// .. further down this class
void EnemyCharacter::destroyEnemyCharacter(cocos2d::Layer* layer, int randomized_tag) {
layer-> removeChild(layer -> getChildByTag(randomized_tag));
}
在我的案例中,我最终使用了 Box2D,将每个对象添加到 CCArray 中,然后在我的更新方法中遍历它们。我认为我的问题仅针对我的需求,因此这可能对任何人都没有用
我的问题是我为敌人角色对象和子弹对象编写的碰撞检测。
符号:
当我用子弹射击 1 个敌方角色时,敌方角色会正常被摧毁。 但是,如果生成了 2 个或更多敌人角色并且我射击了第一个生成的敌人,它什么都不做。 最后一个被生成和射击的角色被毫无问题地摧毁。
我是如何修复它的:
我决定通过创建一个 int 变量给每个敌人角色一个唯一的 ID,并在每次生成敌人时随机化它。 这确保我每个敌人角色对象肯定会有一个唯一的标识符,这样如果我射击他们,我可以以某种方式将那个唯一的 ID 与我的子弹相匹配。
但是,我不知道如何解决这个问题。下面的代码只是删除与任何随机标签相关联的每个敌人角色
我的问题:
我如何设置我的子弹对象来保存我的敌人角色的每个唯一 ID,以便当子弹击中一个(无论具体顺序如何)时它会搜索然后将它具有的唯一 ID 与已击中敌方角色ID?
如果我的问题不清楚或者我的编码风格很糟糕,我们深表歉意。
GameScene.cpp
/**
* @param ENEMY_SPAWN_FREQUENCY value is 0.002, set to make them spawn automatically every few seconds
*/
void GameScene::updateScheduler() {
this -> scheduleUpdate();
this -> schedule(schedule_selector(GameScene::spawnEnemyCharacter), ENEMY_SPAWN_FREQUENCY * visibleSize.width);
}
// ...
bool GameScene::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event) {
// fire button
auto target = (Sprite*)this -> getChildByTag(FIRE_BUTTON_TAG);
Rect rect = target -> getBoundingBox();
Point p = touch -> getLocation();
// initialize bullets
if (rect.containsPoint(p)) {
GameScene::spawnBullets(PLAYER_TAG, playerCharacter->getPositionX(), playerCharacter->getPositionY()+100, 0, REFERENCE_SIZE_Y);
return true;
}
// ...
return false;
}
// ... somewhere below my GameScene.cpp class
void GameScene::spawnBullets(int shooter_id, int x, int y, int p_x, int p_y) {
// load bullet sprites.
SpriteFrameCache::getInstance() -> addSpriteFramesWithFile("bullets.plist");
// ...
auto bulletBody = PhysicsBody::createBox(bullet_sprite -> getContentSize());
bulletBody -> setDynamic(true);
bulletBody -> setGravityEnable(false);
bulletBody -> setCollisionBitmask(BULLET_COLLISION_BITMASK);
bulletBody -> setContactTestBitmask(true);
bullet_sprite -> setPhysicsBody(bulletBody);
bullet_sprite -> setPosition(Point( x, y));
bullet_sprite -> setScale(0.2f);
bullet_sprite -> setTag(BULLET_TAG);
this -> addChild(bullet_sprite);
// animate bullet object so that it shoots
bullet_obj.fireBullet(bullet_sprite, p_x, p_y);
}
// ... somewhere further down this class i define my enemy characters to be spawned as enemy objects in the below method
void GameScene::spawnEnemyCharacter(float dt) {
int random_tag = rand(); // ensure that each enemy character object has a unique random id as its tag
enemyCharacter_obj.spawnEnemy(this, random_tag);
enemy_tags.push_back(random_tag);
// ... destroy enemy characters if hit by bullet:
bool GameScene::onContactBegin( cocos2d::PhysicsContact &contact ) {
PhysicsBody *a = contact.getShapeA() -> getBody();
PhysicsBody *b = contact.getShapeB() -> getBody();
if (BULLET_COLLISION_BITMASK == a->getCollisionBitmask() && ENEMY_COLLISION_BITMASK == b-> getCollisionBitmask() ||
BULLET_COLLISION_BITMASK == b->getCollisionBitmask() && ENEMY_COLLISION_BITMASK == a-> getCollisionBitmask() ) {
// delete enemys with random tag
for (std::vector<int>::iterator itl = enemy_tags.begin(); itl != enemy_tags.end(); ++itl) {
enemyCharacter_obj.destroyEnemyCharacter(this, *itl);
}
this -> removeChild(bullet_sprite);
}
return true;
}
Bullet.cpp
void Bullet::fireBullet(Sprite* bullet_sprite, int x, int y) {
auto bulletAction = Sequence::create( MoveBy::create(BULLETSPEED, Point(x, y)), CallFuncN::create( CC_CALLBACK_1(Bullet::doRemoveFromParentAndCleanup, this, true)), NULL);
bullet_sprite -> runAction(bulletAction);
}
现在我的敌人角色class:
void EnemyCharacter::spawnEnemy(cocos2d::Layer* layer, int random_tag) {
// データ読み込み
SpriteFrameCache::getInstance() -> addSpriteFramesWithFile("enemies.plist");
// 敵キャラクター
enemyCharacter = Sprite::createWithSpriteFrameName("enemy_1.png");
auto enemyCharacterBody = PhysicsBody::createBox(enemyCharacter -> getContentSize() / 5);
// ...
auto enemyCharacterPosition = (random * visibleSize.height ) + ( enemyCharacter -> getContentSize().height / 2);
enemyCharacterBody -> setDynamic(false);
enemyCharacterBody -> setCollisionBitmask(ENEMY_COLLISION_BITMASK);
enemyCharacterBody -> setContactTestBitmask(true);
enemyCharacter -> setScale(0.3f);
enemyCharacter -> setTag(random_tag);
enemyCharacter -> setPhysicsBody(enemyCharacterBody);
enemyCharacter -> setPosition( Point( ((random * visibleSize.width) + (enemyCharacter->getContentSize().width / 2)), visibleSize.height ) );
layer -> addChild(enemyCharacter);
// ...
}
// .. further down this class
void EnemyCharacter::destroyEnemyCharacter(cocos2d::Layer* layer, int randomized_tag) {
layer-> removeChild(layer -> getChildByTag(randomized_tag));
}
在我的案例中,我最终使用了 Box2D,将每个对象添加到 CCArray 中,然后在我的更新方法中遍历它们。我认为我的问题仅针对我的需求,因此这可能对任何人都没有用