According to the unreal documentation, GetRelativeRotation is a member variable of USceneComponent. However, when I run my code, it tells me that it's not. I have tried switching my Camera to a UCameraComponent(as it was originally before I checked the documenation) and still no luck. Any ideas? heres the code for the .cpp file:
#include "FirstPersonCharacter.h"
AFirstPersonCharacter::AFirstPersonCharacter()
{
PrimaryActorTick.bCanEverTick = true;
AutoPossessPlayer = EAutoReceiveInput::Player0;
bUseControllerRotationYaw = false;
Cam = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
Cam->AttachTo(RootComponent);
Cam->SetRelativeLocation(FVector(0.f, 0.f, 40.f)); //places the camera 40cm above the centre of the body.
}
void AFirstPersonCharacter::BeginPlay()
{
Super::BeginPlay();
}
void AFirstPersonCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AFirstPersonCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
InputComponent->BindAxis("HorizontalMovement", this, &AFirstPersonCharacter::HorizontalMove);
InputComponent->BindAxis("VerticalMovement", this, &AFirstPersonCharacter::VerticalMove);
InputComponent->BindAxis("VerticalLook", this, &AFirstPersonCharacter::VerticalRot);
InputComponent->BindAxis("HorizontalLook", this, &AFirstPersonCharacter::HorizontalRot);
}
void AFirstPersonCharacter::HorizontalMove(float value)
{
if (value) //make sure it doesn't constantly call on addmovementinput if theres no value to add to it
{
AddMovementInput(GetActorRightVector(), value);
}
}
void AFirstPersonCharacter::VerticalMove(float value)
{
if (value) //make sure it doesn't constantly call on addmovementinput if theres no value to add to it
{
AddMovementInput(GetActorForwardVector(), value);
}
}
void AFirstPersonCharacter::HorizontalRot(float value)
{
if (value)
{
AddActorLocalRotation(FRotator(0, value, 0));
}
}
void AFirstPersonCharacter::VerticalRot(float value)
{
if (value)
{
float temp = Cam->GetRelativeRotation().Pitch + value; //THIS IS WHERE THE ISSUE IS
if (temp < 65 && temp > -65)
{
Cam->AddLocalRotation(FRotator(value, 0, 0));
}
}
and the code for the header file:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Components/InputComponent.h"
#include "Components/SceneComponent.h"
#include "Camera/CameraComponent.h"
#include "FirstPersonCharacter.generated.h"
UCLASS()
class MOMENTUMPROJECTMAIN_API AFirstPersonCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AFirstPersonCharacter();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
private:
void HorizontalMove(float value);
void VerticalMove(float value);
void HorizontalRot(float value);
void VerticalRot(float value);
//allows me to edit in the editor, without going into source code.
UPROPERTY(EditAnywhere, Category = "Camera")
UCameraComponent* Cam;
};
thanks.
I want to open the door when pressing left mouse button, but nothing happens
OpenDoor.h
UCLASS()
class HOME_API ADoorOpen : public APawn
{
GENERATED_BODY()
public:
ADoorOpen();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
UPROPERTY()
USceneComponent* Root;
UPROPERTY(EditAnywhere)
UStaticMeshComponent* Door;
UPROPERTY(EditAnywhere, Category = "DoorOpen")
float rotateValue;
UPROPERTY(BlueprintReadOnly, Category = "DoorOpen")
FRotator doorRotation;
UPROPERTY(BlueprintReadOnly, Category = "DoorOpen")
bool open;
UFUNCTION(BlueprintCallable, Category = "DoorOpen")
void OpenCloseDoor();
};
OpenDoor.cpp
#include "DoorOpen.h"
#include "DrawDebugHelpers.h"
#include "Engine.h"
ADoorOpen::ADoorOpen()
{
PrimaryActorTick.bCanEverTick = true;
rotateValue = 0.0f;
open = false;
Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
RootComponent = Root;
Door = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Door"));
Door->SetRelativeLocation(FVector(0.f, 50.f, -50.f));
Door->SetupAttachment(RootComponent);
}
void ADoorOpen::OpenCloseDoor()
{
// don't see this while playing
GEngine->AddOnScreenDebugMessage(-1, 0.f, FColor::Red, "OpenCloseDoor");
//...
}
void ADoorOpen::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
// Can't call this
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ADoorOpen::OpenCloseDoor);
}
Increase the display time for AddOnScreenDebugMessage
GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Red, "OpenCloseDoor");
Otherwise, the text will show for just a frame.
First of all thank you for your time and apologize for the long of this post but i couldn't find any other way to make it shorter and also for me english! if you don't understand something, just ask ^^. Hope you can find the error because is driving me crazy.
I'm currently learning DirectX 11 and i'm making This Little Game from this website but applying OOP and DirectX 11 instead of 9 just taking certain things from that project.
Ok, now that you have a little context here is the problem.
I made an abstract class called GameObject which encapsulates all the functionalities concerning to rendering, like storing the image(s), animation, transition between frames, etc. This GameObject class is used to define every other object that will interact in my game.
GameObject Class
////////////////////////////////////////////////////////////////////////////////
// Filename: GameObject.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _GAME_OBJECT_H_
#define _GAME_OBJECT_H_
///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "Sprite.h"
#include "InputHandler.h"
#include "Timer.h"
class GameObject
{
public:
GameObject();
GameObject(const GameObject& other);
~GameObject();
virtual bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen) = 0;
bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen, WCHAR* spriteFileName, Bitmap::DimensionType bitmap, Bitmap::DimensionType sprite, int numberOfFramesAcross, int initialFrame, bool useTimer);
virtual void Shutdown();
virtual bool Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix);
void Move();
void Move(const D3DXVECTOR2 vector);
virtual void Frame(const InputHandler::ControlsType& controls);
void SortFrameArray(const int* framesOrder, int size);
void SetPosition(const POINT& position);
const POINT GetPosition();
void SetVelocity(const D3DXVECTOR2& velocity);
const D3DXVECTOR2 GetVelocity();
void SetStatus(const bool status);
bool GetStatus();
float GetMovementDelayTime();
void ResetMovementDelayTime();
float GetAnimationDelayTime();
void ResetAnimationDelayTime();
//Both of this objects i think i'll remove them from this class. I don't think they belong here.
ID3D11Device* GetDevice();
HWND GetHWND();
Sprite* GetSprite();
protected:
ID3D11Device* m_device;
HWND m_hwnd;
Sprite* m_Sprite;
Timer* m_Timer;
POINT m_position;
D3DXVECTOR2 m_velocity;
bool m_active;
float m_movementDelay;
float m_animationDelay;
};
#endif
Cpp
////////////////////////////////////////////////////////////////////////////////
// Filename: GameObject.cpp
////////////////////////////////////////////////////////////////////////////////
#include "GameObject.h"
GameObject::GameObject()
{
this->m_Sprite = nullptr;
this->m_Timer = nullptr;
this->m_movementDelay = 0.0f;
this->m_animationDelay = 0.0f;
}
GameObject::GameObject(const GameObject& other)
{
}
GameObject::~GameObject()
{
}
bool GameObject::Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen, WCHAR* spriteFileName, Bitmap::DimensionType bitmap, Bitmap::DimensionType sprite, int numberOfFramesAcross, int initialFrame, bool useTimer)
{
bool result;
this->m_device = device;
this->m_hwnd = hwnd;
this->m_Sprite = new Sprite();
if (!this->m_Sprite)
{
return false;
}
result = this->m_Sprite->Initialize(device, hwnd, screen, spriteFileName, bitmap, sprite, numberOfFramesAcross, initialFrame);
if (!result)
{
return false;
}
if (useTimer)
{
this->m_Timer = new Timer();
if (!this->m_Timer)
{
return false;
}
result = this->m_Timer->Initialize();
if (!result)
{
return false;
}
}
return true;
}
void GameObject::Shutdown()
{
SAFE_SHUTDOWN(this->m_Sprite);
SAFE_DELETE(this->m_Timer);
}
bool GameObject::Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
return this->m_Sprite->Render(deviceContext, this->m_position, wordMatrix, viewMatrix, projectionMatrix);
}
void GameObject::Move()
{
this->m_position.x += this->m_velocity.x;
this->m_position.y += this->m_velocity.y;
}
void GameObject::Move(const D3DXVECTOR2 vector)
{
this->m_position.x += vector.x;
this->m_position.y += vector.y;
}
void GameObject::Frame(const InputHandler::ControlsType& controls)
{
if (this->m_Timer)
{
this->m_Timer->Frame();
this->m_movementDelay += this->m_Timer->GetTime();
this->m_animationDelay += this->m_Timer->GetTime();
}
}
void GameObject::SortFrameArray(const int* framesOrder, int size)
{
this->m_Sprite->SortFrameArray(framesOrder, size);
}
void GameObject::SetPosition(const POINT& position)
{
this->m_position = position;
}
const POINT GameObject::GetPosition()
{
return this->m_position;
}
void GameObject::SetVelocity(const D3DXVECTOR2& velocity)
{
this->m_velocity = velocity;
}
const D3DXVECTOR2 GameObject::GetVelocity()
{
return this->m_velocity;
}
void GameObject::SetStatus(const bool status)
{
this->m_active = status;
}
bool GameObject::GetStatus()
{
return this->m_active;
}
Sprite* GameObject::GetSprite()
{
return this->m_Sprite;
}
float GameObject::GetAnimationDelayTime()
{
return this->m_animationDelay;
}
void GameObject::ResetMovementDelayTime()
{
this->m_movementDelay = 0.0f;
}
float GameObject::GetMovementDelayTime()
{
return this->m_animationDelay;
}
void GameObject::ResetAnimationDelayTime()
{
this->m_animationDelay = 0.0f;
}
ID3D11Device* GameObject::GetDevice()
{
return this->m_device;
}
HWND GameObject::GetHWND()
{
return this->m_hwnd;
}
And i made the derived class Fighter which represents my Spaceship and has a FighterFlame which i think is not relevant to the problem, and a list of pointers to pointers of Bullet (m_Bullets) which will be the bullets coming out from the Ship.
////////////////////////////////////////////////////////////////////////////////
// Filename: Fighter.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _FIGHTER_H_
#define _FIGHTER_H_
//////////////
// INCLUDES //
//////////////
#include <list>
///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "GameObject.h"
#include "Bullet.h"
#include "FighterFlame.h"
class Fighter : public GameObject
{
public:
Fighter();
Fighter(const Fighter& other);
~Fighter();
virtual bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen) override;
virtual void Shutdown();
virtual bool Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix) override;
virtual void Frame(const InputHandler::ControlsType& controls) override;
private:
void GenerateTriBullet();
void ValidateBulletsBounds();
private:
int m_life;
int m_lives;
FighterFlame* m_FighterFlame;
std::list<Bullet**> m_Bullets;
const int SHIP_SPEED = 3;
const float MOVEMENT_DELAY = 16.0f;
const float ANIMATION_DELAY = 20.0f;
const float SHOOT_DELAY = 30.0f;
};
#endif
Cpp
////////////////////////////////////////////////////////////////////////////////
// Filename: Fighter.cpp
////////////////////////////////////////////////////////////////////////////////
#include "Fighter.h"
Fighter::Fighter() : GameObject()
{
this->m_life = 100;
this->m_lives = 3;
this->m_FighterFlame = nullptr;
}
Fighter::Fighter(const Fighter& other)
{
}
Fighter::~Fighter()
{
}
bool Fighter::Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen)
{
bool result;
this->m_life = 100;
this->m_lives = 3;
result = GameObject::Initialize(device, hwnd, screen, L"Fighter.dds", Bitmap::DimensionType{ 1152, 216 }, Bitmap::DimensionType{ 144, 108 }, 8, 7, true);
if (!result)
{
MessageBox(hwnd, L"Could not initialize Fighter", L"Error", MB_OK);
return false;
}
this->m_position = POINT{ 0, 0 };
int order[16] = { 7, 6, 5, 4, 3, 2, 1, 0, 8, 9, 10, 11, 12, 13, 14, 15 };
GameObject::SortFrameArray(order, 16);
this->m_FighterFlame = new FighterFlame();
if (!this->m_FighterFlame)
{
return false;
}
result = this->m_FighterFlame->Initialize(device, hwnd, screen);
if (!result)
{
MessageBox(hwnd, L"Could not initialize FighterFlame", L"Error", MB_OK);
return false;
}
return true;
}
bool Fighter::Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
bool result;
result = GameObject::Render(deviceContext, wordMatrix, viewMatrix, projectionMatrix);
if (!result)
{
return false;
}
result = this->m_FighterFlame->Render(deviceContext, wordMatrix, viewMatrix, projectionMatrix);
if (!result)
{
return false;
}
for (Bullet** bullet : this->m_Bullets)
{
if (bullet)
{
result = (*bullet)->Render(deviceContext, wordMatrix, viewMatrix, projectionMatrix);
if (!result)
{
return false;
}
}
}
return true;
}
void Fighter::Shutdown()
{
GameObject::Shutdown();
SAFE_SHUTDOWN(this->m_FighterFlame);
for (Bullet** bullet : this->m_Bullets)
{
SAFE_SHUTDOWN(*bullet);
}
this->m_Bullets.clear();
}
void Fighter::Frame(const InputHandler::ControlsType& controls)
{
GameObject::Frame(controls);
this->m_FighterFlame->SetPosition(POINT{ this->m_position.x - 26, this->m_position.y + 47});
this->m_FighterFlame->Frame(controls);
for (Bullet** bullet : this->m_Bullets)
{
(*bullet)->Frame(controls);
}
if (GameObject::GetMovementDelayTime() > MOVEMENT_DELAY)
{
if (controls.up ^ controls.down)
{
if (controls.up)
{
if (GameObject::GetPosition().y > 0)
{
GameObject::Move(D3DXVECTOR2(0, -SHIP_SPEED));
}
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->IncrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
else if (controls.down)
{
if (GameObject::GetPosition().y < (GameObject::GetSprite()->GetBitmap()->GetScreenDimensions().height - GameObject::GetSprite()->GetBitmap()->GetBitmapDimensions().height))
{
GameObject::Move(D3DXVECTOR2(0, SHIP_SPEED));
}
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->DecrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
}
else
{
if (GameObject::GetSprite()->GetCurrentFrame() > (GameObject::GetSprite()->GetAmountOfFrames() / 2))
{
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->DecrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
if (GameObject::GetSprite()->GetCurrentFrame() < (GameObject::GetSprite()->GetAmountOfFrames() / 2))
{
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->IncrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
}
if (controls.right ^ controls.left)
{
if (controls.right)
{
if (GameObject::GetPosition().x < (GameObject::GetSprite()->GetBitmap()->GetScreenDimensions().width - GameObject::GetSprite()->GetBitmap()->GetBitmapDimensions().width))
{
GameObject::Move(D3DXVECTOR2(SHIP_SPEED, 0));
}
}
else if (controls.left)
{
if (GameObject::GetPosition().x > 0)
{
GameObject::Move(D3DXVECTOR2(-SHIP_SPEED, 0));
}
}
}
GameObject::ResetMovementDelayTime();
}
if (controls.spaceBar)
{
Fighter::GenerateTriBullet();
}
Fighter::ValidateBulletsBounds();
}
void Fighter::GenerateTriBullet()
{
Bullet* upBullet = new Bullet();
upBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
upBullet->SetVelocity(D3DXVECTOR2(20, 2));
upBullet->SetPosition(GameObject::GetPosition());
upBullet->Move();
this->m_Bullets.push_back(&upBullet);
Bullet* middleBullet = new Bullet();
middleBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
middleBullet->SetVelocity(D3DXVECTOR2(20, 0));
middleBullet->SetPosition(GameObject::GetPosition());
middleBullet->Move();
this->m_Bullets.push_back(&middleBullet);
Bullet* downBullet = new Bullet();
downBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
downBullet->SetVelocity(D3DXVECTOR2(20, -2));
downBullet->SetPosition(GameObject::GetPosition());
downBullet->Move();
this->m_Bullets.push_back(&downBullet);
}
void Fighter::ValidateBulletsBounds()
{
for (std::list<Bullet**>::iterator it = this->m_Bullets.begin(); it != this->m_Bullets.end(); it++)
{
if ((*(*(&(it)._Ptr->_Myval)))->GetPosition().x > GameObject::GetSprite()->GetBitmap()->GetScreenDimensions().width)
{
SAFE_SHUTDOWN(**it);
this->m_Bullets.erase(it);
}
}
}
And finally the problematic one, The Bullet class who is also derived from GameObject and will represent the bullets that the spaceship can shoot.
////////////////////////////////////////////////////////////////////////////////
// Filename: Bullet.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _BULLET_H_
#define _BULLET_H_
///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "GameObject.h"
class Bullet : public GameObject
{
public:
Bullet();
Bullet(const Bullet& other);
~Bullet();
virtual bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen) override;
virtual void Frame(const InputHandler::ControlsType& controls) override;
private:
const float MOVEMENT_DELAY = 16.0f;
};
#endif
Cpp
////////////////////////////////////////////////////////////////////////////////
// Filename: Bullet.cpp
////////////////////////////////////////////////////////////////////////////////
#include "Bullet.h"
Bullet::Bullet() : GameObject()
{
}
Bullet::Bullet(const Bullet& other)
{
}
Bullet::~Bullet()
{
}
bool Bullet::Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen)
{
bool result;
result = GameObject::Initialize(device, hwnd, screen, L"Bullet.dds", Bitmap::DimensionType{ 18, 3 }, Bitmap::DimensionType{ 18, 3 }, 1, 0, true);
if (!result)
{
return false;
}
return true;
}
void Bullet::Frame(const InputHandler::ControlsType& controls)
{
GameObject::Frame(controls);
if (GameObject::GetMovementDelayTime() > MOVEMENT_DELAY)
{
GameObject::Move();
}
}
And the problem:
When the Gameloop is running and i press space bar, this occurs
// this if is from Fighter::Frame
if (controls.spaceBar)
{
Fighter::GenerateTriBullet();
}
Fighter::ValidateBulletsBounds();
It enters to the GenerateTriBullet method, which stores 3 bullets on the m_Bullets list.
void Fighter::GenerateTriBullet()
{
Bullet* upBullet = new Bullet();
upBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
upBullet->SetVelocity(D3DXVECTOR2(20, 2));
upBullet->SetPosition(GameObject::GetPosition());
upBullet->Move();
this->m_Bullets.push_back(&upBullet);
Bullet* middleBullet = new Bullet();
middleBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
middleBullet->SetVelocity(D3DXVECTOR2(20, 0));
middleBullet->SetPosition(GameObject::GetPosition());
middleBullet->Move();
this->m_Bullets.push_back(&middleBullet);
Bullet* downBullet = new Bullet();
downBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
downBullet->SetVelocity(D3DXVECTOR2(20, -2));
downBullet->SetPosition(GameObject::GetPosition());
downBullet->Move();
this->m_Bullets.push_back(&downBullet);
}
When it leaves the method, i check the list and the bullets are still there as well as before entering the ValidateBulletsBound, but as soon as it enters the method and before doing ANYTHING, the bullets on the list are simply gone, and with this i mean, the m_Bullets list still has three objects, but happens that they are all NULL.
To explain myself a little better, what i want to do is that every time i press space-bar 3 bullets appears on the screen, and I'm trying to do that by asking if the space-bar value is true, add 3 Bullets to the m_Bullet list, then validate that the bullets in the list are still between the screen space, otherwise remove it.
But as you can see, i successfully store the bullets on the list and as soon as i enter to validate, they are gone... poof!
I don't know why any of this is happening, they are different instance of a class who doesn't share anything between them (memory-wise speaking), there's no static method or pointers shared by then, and even though they would it shouldn't be a problem given that they are just entering in another method and no operation has been done in the middle of that "entering the another method" part, or whatsoever. They even are in the same class, same context, no complex operation or leak (that i know of). I really don't know what's going on!
I want to finish by acknowledging that there are some serious design problems like the one's on GenerateTriBullet, and the fact that i'm not using matrices to move the objects. I'm just trying to finish it first (this is the first game i make on DirectX, really exited btw!!! ), then when i can see the big picture, start to put everything where it belongs. Also, how do i get the value from the list iterator, i read that it was (*it) for simple values, but i have a pointer to a pointer, so i thought it would be **it, but it always resolves to nullptr.
I really hope you can help me.
Here's the project, if you feel like you didn't understand and want to go a little further. You just have to run the project, a ship will appear in a little black window, put a breakpoint on line 182 of the Fighter class then press spacebar on the game window, then from there see what happens with m_Bullets when it leaves GenerateTriBullet and Enters ValidateBulletsBounds.
THANK YOU!
One clear problem:
m_Bullets is a list<Bullet**>. When you add to it you are adding the address of a local variable, e.g.,
Bullet* upBullet = new Bullet();
...
this->m_Bullets.push_back(&upBullet);
Went this method returns, the address stored from the &upBullet expression is no longer valid, as that variable no longer exits.
I think you mean to have m_Bullets as list<Bullet*>, and to add to it:
Bullet* upBullet = new Bullet();
...
this->m_Bullets.push_back(upBullet);
I think the best solution is to let list deal with the memory management and just have m_Bullets as list<Bullet>, then:
this->m_Bullets.emplace_back();
However this will probably require rethinking some of the polymorphism.
can't change the color of a background i have this simple class :
here is the c++ file :
#include "HelloWorldScene.h"
USING_NS_CC;
HelloWorld::HelloWorld()
{
;
}
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !LayerColor::initWithColor(Color4B(20,0,0,255)) )
{
return false;
}
winSize = Director::getInstance()->getWinSize();
visibleSize = Director::getInstance()->getVisibleSize();
origin = Director::getInstance()->getVisibleOrigin();
/////////////////////////////
// 2. add a menu item with "X" image, which is clicked to quit the program
// you may modify it.
// add a "close" icon to exit the progress. it's an autorelease object
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
closeItem->setPosition(Point(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
origin.y + closeItem->getContentSize().height/2));
// create menu, it's an autorelease object
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Point::ZERO);
this->addChild(menu, 1);
schedule( schedule_selector(HelloWorld::tick) );
return true;
}
void HelloWorld::onExit()
{
LayerColor::onExit();
}
void HelloWorld::onEnter()
{
LayerColor::onEnter();
auto cache = SpriteFrameCache::getInstance();
cache->addSpriteFramesWithFile("interface/sprites.plist", "interface/sprites.png");
SpriteBatchNode* batch = SpriteBatchNode::create("interface/sprites.png");
this->addChild(batch,BATCH_Z);
auto listener = EventListenerTouchAllAtOnce::create();
listener->onTouchesBegan = CC_CALLBACK_2(HelloWorld::onTouchesBegan, this);
listener->onTouchesMoved = CC_CALLBACK_2(HelloWorld::onTouchesMoved, this);
listener->onTouchesEnded = CC_CALLBACK_2(HelloWorld::onTouchesEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
void HelloWorld::onTouchesBegan(const std::vector<Touch*>& touches, Event *event)
{
for( auto& touch : touches)
{
}
}
void HelloWorld::onTouchesMoved(const std::vector<Touch*>& touches, Event *event)
{
for( auto& touch : touches)
{
}
}
void HelloWorld::onTouchesEnded(const std::vector<Touch*>& touches, Event *event)
{
for( auto& touch : touches)
{
startAnim = true;
};
}
void HelloWorld::tick(float dt)
{
if(startAnim)
{
}
}
void HelloWorld::draw()
{
LayerColor::draw();
}
HelloWorld::~HelloWorld()
{
// Removes Touch Event Listener
_eventDispatcher->removeEventListener(_touchListener);
}
void HelloWorld::menuCloseCallback(Object* pSender)
{
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
and the h file :
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class GameObj;
class ReelGameObj;
class HelloWorld : public cocos2d::LayerColor
{
public:
HelloWorld();
~HelloWorld();
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::Scene* createScene();
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// a selector callback
void menuCloseCallback(Object* pSender);
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld);
void tick(float dt);
virtual void draw();
virtual void onEnter();
virtual void onExit();
void onTouchesBegan(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event *event);
void onTouchesMoved(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event *event);
void onTouchesEnded(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event *event);
protected:
cocos2d::CustomCommand _customCommand;
void onDraw();
private:
cocos2d::EventListenerTouchOneByOne* _touchListener;
cocos2d::Size winSize;
cocos2d::Size visibleSize;
cocos2d::Point origin;
GameObj* pMainWindowObjCenter;
ReelGameObj* pReelGameObj;
bool startAnim;
};
#endif // __HELLOWORLD_SCENE_H__
and nothing no color in the background , why ?
im working on windows with VC 2012
I think your color is too dark. Try changing the values to (255,25,255,255) and check the result.
I created a sample project (in Beta 2), and only changed these lines:
.h:
class HelloWorld : public cocos2d::LayerColor
.cpp:
if( !LayerColor::initWithColor(Color4B(255,255,255,255)) )
The result is a white background.
I cleaned up and updated your code (I use cocos2dx 2.2.1) and I could change the layer's color to red.
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class HelloWorld : public cocos2d::CCLayerColor
{
public:
HelloWorld();
~HelloWorld();
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::CCScene* createScene();
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// a selector callback
void menuCloseCallback(CCObject* pSender);
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld);
virtual void onEnter();
void draw();
private:
cocos2d::CCSize winSize;
cocos2d::CCSize visibleSize;
cocos2d::CCPoint origin;
bool startAnim;
};
#endif // __HELLOWORLD_SCENE_H__
The cpp file
#include "HelloWorldScene.h"
USING_NS_CC;
HelloWorld::HelloWorld()
{}
HelloWorld::~HelloWorld()
{}
CCScene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = CCScene::create();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
ccColor4B c = ccc4(255,0,0,255);
if ( !CCLayerColor::initWithColor(c) )
{
return false;
}
return true;
}
void HelloWorld::onEnter()
{
CCLayerColor::onEnter();
}
void HelloWorld::draw()
{
CCLayerColor::draw();
}
I'm trying to create a button that is derived from the base class CCMenuItemImage. I want this button to be able to call it's function when it's first touched instead of after the touch ends. However, trying to subclass, I get an error saying it's an invald conversion.
button.ccp:
#include "button.h"
void Button::selected(){
CCLOG("SELECTED");
}
void Button::unselected(){
CCLOG("UNSELECTED");
}
Button* Button::create(const char *normalImage, const char *selectedImage, const char *disabledImage, CCObject* target, SEL_MenuHandler selector) {
Button *button = new Button();
if (button && button->initWithNormalImage(normalImage, selectedImage, disabledImage, NULL, NULL))
{
button->autorelease();
return button;
}
CC_SAFE_DELETE(button);
return NULL;
}
button.h:
#ifndef BUTTON_H
#define BUTTON_H
#include "cocos2d.h"
class Button : public cocos2d::CCMenuItemImage{
public:
virtual void selected();
virtual void unselected();
};
#endif
SinglePlayer.ccp piece:
Button *left1 = Button::create("turncircle.png","turncircle.png", this, menu_selector(SinglePlayer::turning));
MenuItem select() is triggered on touch finished by default.
You need to subclass CCSprite with Touch registered with dispatcher and overwrite the ccTouchBegan
What I can understand is that you are trying to do manual control with the touches of your CCMenuItemImage. Actually all the touches are being handled in CCMenu not in MenuItem so you have to inherit CCMenu rather CCMenuItemImage to override the touches.
In my game I had this problem with CCTableView and CCMenuItem where MenuItem was a prioritised in taking gestures. So I tweaked it with inheriting CCMenu.
It also contain some extra code but just to make everything gets intact I am pasting everything.
ScrollMenu.h Class
class ScrollMenu:public CCMenu
{
public:
ScrollMenu();
virtual ~ScrollMenu(){};
bool isMovedGesture_;
bool istabBar_;
CCMenuItem * previousSelectedItem_;
static ScrollMenu* create(CCMenuItem* item,...);
virtual void registerWithTouchDispatcher();
virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);
virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);
virtual void ccTouchEnded(CCTouch *touch, CCEvent* event);
CREATE_FUNC(ScrollMenu);
};
class ScrollMenuLoader : public cocos2d::extension::CCNodeLoader
{
public:
CCB_STATIC_NEW_AUTORELEASE_OBJECT_METHOD(ScrollMenuLoader, loader);
protected:
CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(ScrollMenu);
};
ScrollMenu.cpp Class
#include "ScrollMenu.h"
ScrollMenu* ScrollMenu::create(CCMenuItem* item, ...)
{
va_list args;
va_start(args, item);
ScrollMenu *pRet = new ScrollMenu();
if (pRet && pRet->initWithItems(item,args))
{
pRet->autorelease();
va_end(args);
return pRet;
}
va_end(args);
CC_SAFE_DELETE(pRet);
return NULL;
}
ScrollMenu::ScrollMenu()
{
isMovedGesture_ = false;
}
void ScrollMenu::registerWithTouchDispatcher()
{
CCDirector* pDirector = CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, false);
}
bool ScrollMenu::ccTouchBegan(CCTouch* touch, CCEvent* event)
{
return CCMenu::ccTouchBegan(touch, event);
}
void ScrollMenu::ccTouchMoved(CCTouch* touch, CCEvent* event)
{
CC_UNUSED_PARAM(event);
CCAssert(m_eState == kCCMenuStateTrackingTouch, "[Menu ccTouchMoved] -- invalid state");
isMovedGesture_ = true;
}
void ScrollMenu::ccTouchEnded(CCTouch *touch, CCEvent* event)
{
CC_UNUSED_PARAM(touch);
CC_UNUSED_PARAM(event);
CCAssert(m_eState == kCCMenuStateTrackingTouch, "[Menu ccTouchEnded] -- invalid state");
CCMenuItem * currentItem = this->itemForTouch(touch);
if(!currentItem && isMovedGesture_ && m_pSelectedItem)
{
if(!istabBar_ || (previousSelectedItem_ && previousSelectedItem_ != m_pSelectedItem))
{
m_pSelectedItem->unselected();
}
}
else if(currentItem)
{
if(currentItem == m_pSelectedItem)
{
if(!isMovedGesture_)
{
m_pSelectedItem->activate();
previousSelectedItem_ = m_pSelectedItem;
}
else{
if(previousSelectedItem_ != m_pSelectedItem)
{
m_pSelectedItem->unselected();
}
}
}
else
{
if(isMovedGesture_)
{
m_pSelectedItem->unselected();
m_pSelectedItem = currentItem;
m_pSelectedItem->activate();
previousSelectedItem_ = m_pSelectedItem;
}
}
if (!istabBar_) {
currentItem->unselected();
}
}
m_eState = kCCMenuStateWaiting;
isMovedGesture_ = false;
}