Player Bullets going the wrong way and Enemy bullets not firing - c++

Bit of a major predicament as the largest aspect of my game seems to be non-functioning.
I'm making a 3D space invaders game and I'm trying to get the player(and enemies) to fire bullets at each other. But neither seem to be doing so.
I have an attack manager for both that handles their code.
/**
* Prepares a bullet for firing if the current time is greater than
* the last fired time + the firing delay. This purpose of this is to
* put a delay between each bullet as it is fired. A bullet is only
* 'readied' for firing if it is available, i.e. it's alive property
* is set to false.
*
*/
void PlayerAttackManager::fireBullet() {
if ( mCurrentTime > ( mLastFiredTime + sFIRE_DELAY ) ) {
// Find the next available bullet (if one exists)
std::vector<Bullet>::iterator end = mBullets.end();
std::vector<Bullet>::iterator curr = mBullets.begin();
for ( ; curr != end && (*curr).alive() == true; ++curr );
// If there is a bullet available.
if ( curr != end ) {
// Move bullet to firing location and set alive.
Vector3 bulletPos = mSceneMgr->getSceneNode( "PlayerParentNode" )->getPosition();
Vector3 bulletDir = mSceneMgr->getSceneNode( "PlayerParentNode" )->getOrientation() * Vector3::UNIT_Z;
// Pass the initial screen position and direction of travel for the bullet.
(*curr).reset( bulletPos, bulletDir );
}
mLastFiredTime = mCurrentTime;
}
}
The above method is called every time the space bar is pressed but it sends one enemy bullet from the player's position moving downwards and another from above the player moving downwards.
The enemies should attack(one every second) which is called for the EnemyAttackManager to fire from the main.cpp frameRenderingQueued method
The EnemyAttackManager's update is as follows:
void EnemyAttackManager::update(Real const & timeSinceLastFrame, string name)
{
mName = name;
std::vector<Bullet>::iterator end = mBullets.end();
std::vector<Bullet>::iterator curr = mBullets.begin();
for ( ; curr != end && (*curr).alive() == true; ++curr ) {
if ( curr != end ) {
// Move bullet to firing location and set alive.
Vector3 bulletPos = mSceneMgr->getSceneNode( mName + "Node" )->getPosition();
Vector3 bulletDir =mSceneMgr->getSceneNode(mName+ "Node" )->getOrientation() * Vector3::UNIT_Z;
// Pass the initial screen position and direction of travel for the bullet.
(*curr).reset( bulletPos, bulletDir );
(*curr).update(timeSinceLastFrame);
}
}
// Add time since last frame.
mCurrentTime += timeSinceLastFrame;
}
And the bullet's update and reset functions are these respectively:
void Bullet::update( Real const & timeSinceLastFrame ) {
mTtl -= timeSinceLastFrame;
if ( mTtl <= 0 ) {
mNode->setVisible( false );
}
else {
Enemy* enem = new Enemy();
mNode->translate( sMOVE * mDir * timeSinceLastFrame, Node::TS_LOCAL );
// Retrieve a list of possible enemies.
std::vector<Enemy *> enemyVec = enem->getEnemies();
std::vector<Enemy *>::iterator curr = enemyVec.begin();
std::vector<Enemy *>::iterator end = enemyVec.end();
// Check if the ray intersected any of the enemies
for ( ; curr != end && !CollisionManager::instance()->rayIntersects( mNode->getPosition(), 0, (*curr)->meshName(), mDir )
; ++curr );
if ( curr != end ) { // if bullet has collided with an enemy.
//(*curr)->applyDamage();
mTtl = 0;
//JetPack3D::score += 10;
mNode->setVisible( false );
}
//Check the current bullet pos vs. player
}
}
void Bullet::reset( Vector3 const & bulletPos, Vector3 const & bulletDir ) {
mNode->setPosition( bulletPos );
mNode->setVisible( true );
mTtl = sLIFE_TIME;
mDir = bulletDir;
// Need to reverse x and z components so bullet fires forward into the scene.
//now need it to fire right?
mDir.z *= -1;
mDir.x *= -1;
}
So my question is: How do I make the enemies and the player fire bullets(enemies firing at all and player in the right direction)

Related

Why setPosition work in some condition but doesn't work in other condition?

i make a game let's say ThrowBall, the Player can pick up the ball spawned and throw it into target get the score added then the ball return it's position and repeat. The problem is when Ball dragged by Player (i make the Ball as child of Player) into target, the Ball return it's position correctly into desired position, but the odd happens when it collided after i send the Ball into target by applying impulse it won't return the ball into desired position, why is this happening?
i'm running this game for android, i'm running this code in VS'17 using cocos2d-x-3.17. I tried changing impulse into force, moveby. I tried making the ball stop (setVelocity to zero before setPosition). I tried changing Point into Vect, vec2. I tried to break point debug, the code do read setPosition but do nothing.
GameScene.cpp
bool GameScene::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto pickupListener = EventListenerPhysicsContact::create();
pickupListener->onContactBegin = CC_CALLBACK_1(GameScene::onContactBegin, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(pickupListener, this);
return true;
}
bool GameScene::onContactBegin(cocos2d::PhysicsContact &contact)
{
PhysicsBody *a = contact.getShapeA()->getBody();
PhysicsBody *b = contact.getShapeB()->getBody();
if (
(BALL_COLLISION_BITMASK == a->getCollisionBitmask() && PLAYER_COLLISION_BITMASK == b->getCollisionBitmask()) ||
(BALL_COLLISION_BITMASK == b->getCollisionBitmask() && PLAYER_COLLISION_BITMASK == a->getCollisionBitmask())
)
{
// make the ball follow Player
isfollow = true;
}
else if (
(BALL_COLLISION_BITMASK == a->getCollisionBitmask() && TARGET_COLLISION_BITMASK == b->getCollisionBitmask()) ||
(BALL_COLLISION_BITMASK == b->getCollisionBitmask() && TARGET_COLLISION_BITMASK == a->getCollisionBitmask())
)
{
isfollow = false;
// add score
score++;
__String *tempScore = __String::createWithFormat("%i", score);
scoreLabel->setString(tempScore->getCString());
// return spawn ball
ball->returnPos();
return false;
}
void GameScene::throwBall() {
if (isfollow == true) {
isfollow = false;
ball->getSprite()->getPhysicsBody()->applyImpulse(Vec2(100000, 100000));
}
}
Ball.h
class Ball
{
public:
Ball(cocos2d::Layer *layer);
cocos2d::Sprite *getSprite() { return randomSpawn; };
void returnPos();
private:
cocos2d::Size visibleSize;
cocos2d::Vec2 origin;
cocos2d::Sprite *randomSpawn;
};
Ball.cpp
Ball::Ball(cocos2d::Layer *layer)
{
visibleSize = Director::getInstance()->getVisibleSize();
origin = Director::getInstance()->getVisibleOrigin();
randomSpawn = Sprite::create("res/ball.png");
randomSpawn->setPosition(Vec2(400, 80));
auto randomBallBody = PhysicsBody::createCircle(randomSpawn->getContentSize().width / 2);
randomBallBody->setCollisionBitmask(BALL_COLLISION_BITMASK);
randomBallBody->setContactTestBitmask(true);
randomBallBody->setGravityEnable(false);
randomSpawn->setPhysicsBody(randomBallBody);
layer->addChild(randomSpawn);
}
void Ball::returnPos()
{
randomSpawn->setPosition(Vec2(400, 80));
}
i want to make the object (Ball) return position when collided into Target and repeat. i'm sorry if the format is a mess, i'm new here, also it's not my full code, it's actually works fine i can run it, but only the setPosition won't work

Cocos2d C++ Score system

So I am working on this game and I want to implement a score system.
This is the first time I am working with Cocos2d.
I tried a couple of things but didn't really had succes.
I would like it if for each enemy that gets removed from the scene a int with the name score would be increased by one.
Do you guys have some suggestions ?
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
using namespace CocosDenshion;
USING_NS_CC;
#define BACKGROUND_MUSIC_SFX "bee.mp3"
#define PEW_PEW_SFX "splatter.mp3"
// These bit masks define the physics categories; monster + projectile with two values to specify no type or all types, I use this to see what objects are allowed to collide
enum class PhysicsCategory {
None = 0,
Monster = (1 << 0), // 1
Projectile = (1 << 1), // 2
All = PhysicsCategory::Monster | PhysicsCategory::Projectile // 3
};
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object, turn psysics on
auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setGravity(Vec2(0,0));
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_NONE);
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer child to scene
scene->addChild(layer);
// return scene
return scene;
}
// initialize instance
bool HelloWorld::init()
{
// call the super class’s init method, if succeeds proceed HelloWorldScene‘s setup
if ( !Layer::init() ) {
return false;
}
// get window bounds using game Director singleton.
auto origin = Director::getInstance()->getVisibleOrigin();
auto winSize = Director::getInstance()->getVisibleSize();
// create a DrawNode to draw a green rectangle that fills the screen
auto background = DrawNode::create();
background->drawSolidRect(origin, winSize, Color4F(0.0,0.6,0.0,0.7));
this->addChild(background);
// create the player sprite, position 10% from the left edge of the screen, centered vertically
_player = Sprite::create("player.png");
_player->setPosition(Vec2(winSize.width * 0.1, winSize.height * 0.5));
this->addChild(_player);
// seed the random number generator
srand((unsigned int)time(nullptr));
this->schedule(schedule_selector(HelloWorld::addMonster), 1.5);
auto eventListener = EventListenerTouchOneByOne::create();
eventListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(eventListener, _player);
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegan, this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);
SimpleAudioEngine::getInstance()->playBackgroundMusic(BACKGROUND_MUSIC_SFX, true);
return true;
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
return;
#endif
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
void HelloWorld::addMonster(float dt) {
auto monster = Sprite::create("monster.png");
//Create a PhysicsBody for the sprite, Physics bodies represent the object in Cocos2d physics simulation.
auto monsterSize = monster->getContentSize();
auto physicsBody = PhysicsBody::createBox(Size(monsterSize.width , monsterSize.height),
PhysicsMaterial(0.1f, 1.0f, 0.0f));
//Set the sprite to be dynamic. physics engine will not apply forces to the bear.
physicsBody->setDynamic(true);
// set the category, collision and contact test bit masks:
physicsBody->setCategoryBitmask((int)PhysicsCategory::Monster);
physicsBody->setCollisionBitmask((int)PhysicsCategory::None);
physicsBody->setContactTestBitmask((int)PhysicsCategory::Projectile);
monster->setPhysicsBody(physicsBody);
// create a bear sprite and place it offscreen to the right, random y position
auto monsterContentSize = monster->getContentSize();
auto selfContentSize = this->getContentSize();
int minY = monsterContentSize.height/2;
int maxY = selfContentSize.height - monsterContentSize.height/2;
int rangeY = maxY - minY;
int randomY = (rand() % rangeY) + minY;
monster->setPosition(Vec2(selfContentSize.width + monsterContentSize.width/2, randomY));
this->addChild(monster);
// random duration for bear, each bear will move the same distance across the screen, varying the duration results in bears with random speeds.
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int randomDuration = (rand() % rangeDuration) + minDuration;
// move the bear across the screen.
auto actionMove = MoveTo::create(randomDuration, Vec2(-monsterContentSize.width/2, randomY));
auto actionRemove = RemoveSelf::create();
monster->runAction(Sequence::create(actionMove,actionRemove, nullptr));
}
bool HelloWorld::onTouchBegan(Touch *touch, Event *unused_event) {
// 1 - get the _player object
//auto node = unused_event->getCurrentTarget();
// coordinate of the click within the scene’s coordinate system, calculate the offset of this point from the current position. vector math.
Vec2 touchLocation = touch->getLocation();
Vec2 offset = touchLocation - _player->getPosition();
// If offset‘s x value is negative, the player tries to shoot backwards,return without firing.
if (offset.x < 0) {
return true;
}
// Create projectile, add to screen
auto projectile = Sprite::create("projectile.png");
projectile->setPosition(_player->getPosition());
auto projectileSize = projectile->getContentSize();
auto physicsBody = PhysicsBody::createCircle(projectileSize.width/2 );
physicsBody->setDynamic(true);
physicsBody->setCategoryBitmask((int)PhysicsCategory::Projectile);
physicsBody->setCollisionBitmask((int)PhysicsCategory::None);
physicsBody->setContactTestBitmask((int)PhysicsCategory::Monster);
projectile->setPhysicsBody(physicsBody);
this->addChild(projectile);
// call normalize() to convert the offset into a unit vector, which is a vector of length 1. Multiplying that by 1000 that points in the direction of the user’s tap.
offset.normalize();
auto shootAmount = offset * 1000;
// Adding the vector to the projectile’s position gives the target position.
auto realDest = shootAmount + projectile->getPosition();
// move the projectile to the target position, remove after 5 sec.
auto actionMove = MoveTo::create(5.0f, realDest);
auto actionRemove = RemoveSelf::create();
projectile->runAction(Sequence::create(actionMove,actionRemove, nullptr));
SimpleAudioEngine::getInstance()->playEffect(PEW_PEW_SFX);
return true;
}
// PhysicsContact passed to this method is collision, remove at the end
bool HelloWorld::onContactBegan(PhysicsContact &contact) {
auto nodeA = contact.getShapeA()->getBody()->getNode();
auto nodeB = contact.getShapeB()->getBody()->getNode();
nodeA->removeFromParent();
nodeB->removeFromParent();
return true;
}
I'm not sure that I have fully understood your question, but it seems that you want to create a label to show the current score.
Of course you will need a variable to keep track of your score. Let's assume the variable is an integer and it's called m_score.
You will then need to create and add a Label to your scene. In your init() function add:
m_scoreLabel = Label::createWithTTF(std::to_string(m_score), "fonts/Arial.ttf", 36);
this->addChild(m_scoreLabel);
You will need m_scoreLabel to keep a reference to your Label so that you will be able to change its display text later on. Now, whenever you change the score, first update the value of m_score and then to update the text shown by the label call:
m_scoreLabel->setString(std::to_string(m_score));

C++ Box2D Iterate through vector of bodies and deleting

I have created a game which uses a color coded image to create different bodies/fixtures. So for example if the pixel is red it will get stored into an array as 7 and then the program will create a body called jewel. If there are 10 red pixels, 10 jewels will be created:
else if (array[w][h]==7)
{
b2BodyDef Jewel_BodyDef;
Jewel_BodyDef.position.Set(x, y);
m_collectableJewel = m_world->CreateBody(&Jewel_BodyDef);
b2PolygonShape box;
box.SetAsBox(0.5f, 0.5f);
m_collectableJewelFixture=m_collectableJewel->CreateFixture(&box, 0.0f);
collide.m_jewelFix.push_back(m_collectableJewelFixture);
jewels a;
a.jewel_dim.set(1.0f,1.0f);
a.jewel_pos.set(x,y);
m_jewels.push_back(a);
x+=5.0f;
}
My problem is when calculating the collision between the player and the jewels. The program knows when the player has collided with a jewel. However, I can't get it to delete the fixture. Or rather, it will only delete the last fixture placed, i.e. the last one to be created in the vector. Is there a way to name the fixtures individually? So that then the program can delete the one it has actually collided with, rather than the last one?
edit:
int Collision_with_Player::PickJewel(b2Fixture *player, b2Fixture *foot)
{
int CollisionJewel=0;
std::vector<MyContact>::iterator posi;
for(posi = m_contactListener->m_contacts.begin(); posi != m_contactListener->m_contacts.end(); ++posi)
{
MyContact contact = *posi;
for(std::vector<b2Body*>::iterator iterb = m_jewelBodyVec.begin(); iterb != m_jewelBodyVec.end(); ++iterb)
{
for(std::vector<b2Fixture*>::iterator iter = m_jewelFix.begin(); iter != m_jewelFix.end(); ++iter)
{
if ((contact.fixtureA == player && contact.fixtureB == *iter) ||
(contact.fixtureA ==*iter && contact.fixtureB == player))
{
m_deleteJewels.clear();
std::cout<<"size"<<m_deleteJewels.size()<<std::endl;
CollisionJewel=1;
std::cout<<"Jewel"<<*iter<<std::endl;
deletejewel = *iter;
deletejewelbody= *iterb;
}
else
{
CollisionJewel=0;
}
}
}
}
return CollisionJewel;
}
and in another file
if (collide.PickJewel(m_playerFixture, m_footSensorFixture)==1)
{
collide.deletejewelbody->DestroyFixture(collide.deletejewel);
}

How to move an entity with a mouse click?

Ok i now manage to figure out the problem but now another issue appear, my robot seem to move on its own to another point which i have no idea where its from. Here my code
His code make this robot move to the location i click on the terrain.
bool DemoApp::nextLocation(void){
mDestination = mtoward;
mRobotDir = mDestination - mRobotNode[0]->getPosition();
mDistance = mRobotDir.normalise();
return true;
}
bool DemoApp::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
if (mRobotDir == Ogre::Vector3::ZERO) {
if (nextLocation()) {
// Set walking animation
mAnimationState = mRobot[0]->getAnimationState("Walk");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
}//if
}else{
Ogre::Real move = mWalkSpeed * evt.timeSinceLastFrame;
mDistance -= move;
if (mDistance <= 0.0f){
mRobotNode[0]->setPosition(mDestination);
mRobotDir = Ogre::Vector3::ZERO;
// Set animation based on if the robot has another point to walk to.
if (!nextLocation()){
// Set Idle animation
mAnimationState = mRobot[0]->getAnimationState("Idle");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
}else{
// Rotation Code will go here later
Ogre::Vector3 src = mRobotNode[0]->getOrientation() * Ogre::Vector3::UNIT_X;
if ((1.0f + src.dotProduct(mRobotDir)) < 0.0001f) {
mRobotNode[0]->yaw(Ogre::Degree(180));
}else{
Ogre::Quaternion quat = src.getRotationTo(mRobotDir);
mRobotNode[0]->rotate(quat);
} // else
}//else
}else{
mRobotNode[0]->translate(mRobotDir * move);
} // else
} // if
mAnimationState->addTime(evt.timeSinceLastFrame);
}
Here is the raycast code for my mouse click
Ogre::Terrain* pTerrain = mTerrainGroup->getTerrain(0, 0);
Ogre::Viewport* vp = this->mWindow->getViewport(0);
Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(static_cast<float>(mMouse->getMouseState().X.abs)/mMouse->getMouseState().width, static_cast<float>(mMouse->getMouseState().Y.abs)/mMouse->getMouseState().height);
std::pair <bool, Ogre::Vector3> result;
result = pTerrain->rayIntersects(mouseRay, true, 0);
if (result.first = true)
{
mtoward = result.second - mRobotNode[0]->_getDerivedPosition();
mRobotNode[0]->translate(mtoward, Ogre::Node::TS_LOCAL);
}

Algorithm for Calculating Directional Movement

I'm trying to write a basic Asteroids game in C++ using SFML. While I'm able to move my triangle (the player) around rather easily, the way in which it moves I'm not quite satisfied with.
Currently, the movement isn't relative to the direction it's facing. For example, if I press "w" to move forward, the triangle will simply move up the screen regardless of its direction.
What I'd like for the triangle to do is move forward when the "w" key is pressed, but make the actual direction its moving (in respect to the dimensions of the screen) relative to the actual direction its facing.
So, if the forward tip of the triangle is facing right, when "W" is pressed, it will move right. If "S" is pressed in this case, it will move left. "A" would make it move up, and of course "D" would make it move down.
My current code does not accomplish this one bit - I think there's a really hacky solution to this, but I'd rather approach this from a more mathematical and elegant perspective if possible.
So, what would be the best way to accomplish this?
I have three methods of relevance: one for handling keyboard input, the other for handling mouse movement, and an update method.
Code
void Game::OnKeyPress( void )
{
int count = 0;
const float playerCenterMag = Magnitude( mPlayer.GetShape().GetCenter() );
//Shoddy attempt resulting in absolutely nothing of note
const float moveRateX = ( cosf( mMouseAoR ) * playerCenterMag ) + mPlayer.MoveSpeed;
const float moveRateY = ( sinf( mMouseAoR ) * playerCenterMag ) + mPlayer.MoveSpeed;
if ( mInput.IsKeyDown( sf::Key::W ) ) // Up
{
mPlayer.Position.y -= moveRateY;
++count;
}
if ( mInput.IsKeyDown( sf::Key::S ) ) // Down
{
mPlayer.Position.y += moveRateY;
++count;
}
if ( mInput.IsKeyDown( sf::Key::A ) ) // Left
{
mPlayer.Position.x -= moveRateX;
++count;
}
if ( mInput.IsKeyDown( sf::Key::D ) ) // Right
{
mPlayer.Position.x += moveRateX;
++count;
}
std::cout << "Key Press Rate => " << count << " seconds" << std::endl;
}
void Game::OnMouseEvent( void )
{
mPlayer.GetShape().Rotate( mMouseAoR + 5 );
}
void Game::Update( void )
{
const int x = mInput.GetMouseX();
const int y = mInput.GetMouseY();
mMouseAoR = ( y == 0 ) ? 0
: tanf( x / y );
PrintInfo();
}
There are two versions of this game. If you want, say, 'W' to "thrust" forward, then you need to add moveRate at each cycle and use W to change the rate.
Here apparently you move only if a button is pressed, so you need to update always both X and Y:
if ( mInput.IsKeyDown( sf::Key::W ) ) // Up
{
mPlayer.Position.x += moveRateX;
mPlayer.Position.y += moveRateY;
++count;
}
The moveRate changes according to orientation. When moving laterally, you would do
mPlayer.Position.x += moveRateY;
mPlayer.Position.y += moveRateX;
when moving left (or right), and -= in the other direction.