I am trying to set a camera shake for my character in Unreal C++.
Currently, I declare the instance variable in my header class.
Using log outputs, the code is reaching the right location in the OnFire() function, meaning none of the pointers are null. But the camera shake doesn't work.
UPROPERTY(EditAnywhere)
UCameraShake* CShake;
// And here is how I call it
void AZombieCharacter::BeginPlay(){
SetUpCameraShake();
}
...
void AZombieCharacter::OnFire() {
...
auto CTRLR = UGameplayStatics::GetPlayerController(GetWorld(), 0);
if (CTRLR) {
auto CM = CTRLR->PlayerCameraManager;
if (CM) {
CM->PlayCameraShake(CShake->GetClass(), 1.0f);
}
else {
UE_LOG(LogTemp, Warning, TEXT("CANNOT FIND CM"));
}
}
else {
UE_LOG(LogTemp, Warning, TEXT("CANNOT FIND CTRLR"));
}
}
...
void AZombieCharacter::SetUpCameraShake() {
CShake = UCameraShake::StaticClass()->GetDefaultObject<UCameraShake>();
CShake->OscillationDuration = 4.f;
CShake->OscillationBlendInTime = 0.5f;
CShake->OscillationBlendOutTime = 0.5f;
CShake->RotOscillation.Pitch.Amplitude = FMath::RandRange(5.0f, 10.0f);
CShake->RotOscillation.Pitch.Frequency = FMath::RandRange(25.0f, 35.0f);
CShake->RotOscillation.Yaw.Amplitude = FMath::RandRange(5.0f, 10.0f);
CShake->RotOscillation.Yaw.Frequency = FMath::RandRange(25.0f, 35.0f);
}
Thanks.
Play Camera Shake Accepts an UClass / TSubClassOf<UCameraShake> knowing that would expect us to think that this function would eventually construct a new object and ignore the default object options.
I would recommend to subclass the UCameraShake class and use TSubClassOf to store your class type instead of the pointer like CShake. As it may be garbage collected without you knowing who knows?
Here is a C++ tutorial on UCameraShake's.
https://unrealcpp.com/camera-shake/
The reason your shake is not playing is likely having no actual parameters passed to the shake. Only the default ones despite your try to set the default values, it does not seem to take it into account for newly created objects.
Related
I'm attempting to use SpawnActor() to spawn random actors from an array of classes. I've spent several years using UE4/UE5 blueprints, but this is my first time working in cpp in a long time. The trouble I'm running into is with the SpawnActor function, maybe I'm hooking up the parameters wrong.
Below is the code for my spawning logic in my cpp file:
void ADS_Generator::SpawnFlora()
{
FHitResult CurrentHit;
FActorSpawnParameters SpawnInfo;
for (int F = 0; F < FloraIterations; ++F)
{
if (SpawnedFlora.Num() <= MaxFlora)
{
CurrentHit = SpawnLineTrace(Vertices[FMath::RandRange(0, Vertices.Num() - 1)]);
if (CurrentHit.bBlockingHit == true)
{
if (FMath::RandRange(1, 100) >= FloraTolerance)
{
AActor* CurrentFlora = GetWorld()->SpawnActor(Flora[0], CurrentHit.ImpactPoint, FVector(0, 0, FMath::RandRange(-180, 180)), SpawnInfo);
SpawnedFlora.Add(CurrentFlora);
}
}
}
}
}
Below is the code for my header file where I declare the array of actor classes:
UPROPERTY(EditAnywhere)
TArray<TSubclassOf<class AActor>> Flora;
UPROPERTY(EditAnywhere)
TArray<TSubclassOf<class AActor>> Fauna;
The specific error I'm getting is this:
"C++ no instance of overloaded function matches the argument list
argument types are: (TSubclassOf<AActor>, FVector_NetQuantize, FVector, FActorSpawnParameters)
object type is: UWorld"
I've tried adding "::StaticClass()" as well as using "->StaticClass" to no avail.
Any thoughts or advice? I definitely need to watch some videos and brush up on my cpp, I'm very rusty.
Note: I'm using Flora[0] as a placeholder instead of randomizing the array index just to test.
Found the issue! The problem was my Rotation was defined as a plain FVector, but it needed to be converted to a rotation and then a quaternion, respectively. Below is the code, but fixed:
void ADS_Generator::SpawnFlora()
{
FHitResult CurrentHit;
FActorSpawnParameters SpawnInfo;
for (int F = 0; F < FloraIterations; ++F)
{
if (SpawnedFlora.Num() <= MaxFlora)
{
CurrentHit = SpawnLineTrace(Vertices[FMath::RandRange(0, Vertices.Num() - 1)]);
if (CurrentHit.bBlockingHit == true)
{
UE_LOG(LogTemp, Warning, TEXT("HIT!"));
if (FMath::RandRange(1, 100) >= FloraTolerance)
{
FTransform SpawnLoc;
SpawnLoc.SetLocation(CurrentHit.ImpactPoint);
SpawnLoc.SetRotation((FVector(0, 0, FMath::RandRange(-180, 180)).Rotation().Quaternion()));
SpawnLoc.SetScale3D(FVector(1, 1, 1));
AActor* CurrentFlora = GetWorld()->SpawnActor<AActor>(Flora[0]->StaticClass(), SpawnLoc, SpawnInfo);
SpawnedFlora.Add(CurrentFlora);
UE_LOG(LogTemp, Warning, TEXT("Spawned Flora!"));
}
}
else if(CurrentHit.bBlockingHit == false)
{
UE_LOG(LogTemp, Warning, TEXT("NO HIT"));
}
}
}
}
TLDR; Locations and Rotations are stored differently and I totally forgot.
I am trying to add a lean function to my c++ project, after calculating the YawDelta I want to displayed to my screen using the GEngine->AddOnScreenDebugMessage()
the problem it's always 0 in the viewport screen when pressing play
here is my c++ code of the Lean function which is called in UpdateAnimationProperties (Tick)
void UShooterAnimInstance::Lean(float DeltaTime)
{
if (ShooterCharacter == nullptr) return;
CharacterYawLastFrame = CharacterYaw;
CharacterYaw = ShooterCharacter->GetActorRotation().Yaw;
const float Target{ (CharacterYaw - CharacterYawLastFrame) / DeltaTime };
const float Interp{ FMath::FInterpTo(YawDelta, Target, DeltaTime, 6.f) };
YawDelta = FMath::Clamp(Interp, -90.f, 90.f);
if (GEngine) GEngine->AddOnScreenDebugMessage(5,
-1,
FColor::Cyan,
FString::Printf(TEXT("YawDelta : %f"),
YawDelta));
}
PS: if I use UE_LOG, the output log shows the variable 2 times, one with the correct value and the other one is always 0
Please help
Have you tried calling the AddOnScreenDebugMessage with YawDelta in the AnimInstance's NativeUpdateAnimation ? Try it there after Super::NativeUpdateAnimation(DeltaSeconds)and see what result you get.
I am new to C++/JUCE. I have been working to get a basic synth running and just testing some things out to learn the ropes.
It’s working fine already. But I’m still just learning my way around C++/JUCE and how to declare or access classes/objects/variables.
I’m trying to make a modification to something that I’m stuck with.
I have the following (just excerpts to demonstrate)…
This is where the synthesizer level is set:
struct SineWaveVoice : public SynthesiserVoice
{
SineWaveVoice() {}
bool canPlaySound (SynthesiserSound* sound) override
{
return dynamic_cast<SineWaveSound*> (sound) != nullptr;
}
void startNote (int midiNoteNumber, float velocity,
SynthesiserSound*, int /*currentPitchWheelPosition*/) override
{
currentAngle = 0.0;
level = velocity * 0.15;
tailOff = 0.0;
Ie. Level is set by velocity * 0.15.
In my test set up, I already have a level knob defined under MainContentComponent like this:
class MainContentComponent : public AudioAppComponent,
private Timer
{
public:
MainContentComponent()
: synthAudioSource(keyboardState),
keyboardComponent(keyboardState, MidiKeyboardComponent::horizontalKeyboard)
{
LabeledSlider* control = new LabeledSlider("Frequency");
control->slider.setRange(20.0, 20000.0);
control->slider.setSkewFactorFromMidPoint(500.0);
control->slider.setNumDecimalPlacesToDisplay(1);
control->slider.setValue(currentFrequency, dontSendNotification);
control->slider.onValueChange = [this] { targetFrequency = frequency.slider.getValue(); };
control->slider.setTextBoxStyle(Slider::TextBoxBelow, false, 100, 20);
control->slider.setRange(50.0, 5000.0);
control->slider.setSkewFactorFromMidPoint(500.0);
control->slider.setNumDecimalPlacesToDisplay(1);
addAndMakeVisible(knobs.add(control));
control = new LabeledSlider("Level");
control->slider.setRange(0.0, 1.0);
control->slider.onValueChange = [this] { targetLevel = (float)level.slider.getValue(); };
addAndMakeVisible(knobs.add(control));
....
private:
{
float currentLevel = 0.1f, targetLevel = 0.1f;
LabeledSlider level{ "Level" };
So let’s say I want to use this level slider variable “targetLevel” to be multiplied by the velocity in the “struct” above instead of 0.15.
What do I need to type up there to be able to access and use “targetLevel”? I tried multiple things but I can’t quite figure it out.
Thanks
I am assuming that your SineWaveVoice lies within your SynthAudioSource class and that the voice is a part of a Synthesizer object. To access anything within your SineWaveVoice struct from MainContentComponent you need to expose this somehow via the SynthAudioSource. So my suggestion is that in your SynthAudioSource add a method like this:
void setLevel(double lvl)
{
for (auto i=0; i<synth.getNumVoices(); i++)
{
SineWaveVoice *v = dynamic_cast<SineWaveVoice *>(synth.getVoice(i));
v->level = lvl * v->velocity;
}
}
Then to access this in your MainContentComponent you just do this:
control->slider.onValueChange = [this] {
targetLevel = (float)level.slider.getValue();
synthAudioSource.setLevel(targetLevel);
};
However, notice that this value will be overwritten every time you get a new startNote event. So you should probably store a copy of target level in your SineWaveVoice and multiply with that rather than 0.15.
I'm having problem with the strings in cocos2dx & C++. I want to pass the variable background to Sprite::create(background) however, I get an error. If it was in java the following code will work, but since I'm not used to C++ it may be different. Plus, if it was a int how will I pass it ? How will I be able to solve this? Some tips or samples will be great! I will love to hear from you!
void GameLayer::initBackground()
{
UserDefault *_userDef = UserDefault::getInstance();
//int型
auto _int =_userDef->getIntegerForKey("back");
auto string background = "Background1.png";
if (_int == 0) {
background = "Background2.png";
}
auto bgForCharacter = Sprite::create(background);
bgForCharacter->setAnchorPoint(Point(0, 1));
bgForCharacter->setPosition(Point(0, WINSIZE.height));
addChild(bgForCharacter, ZOrder::BgForCharacter);
auto bgForPuzzle = Sprite::create("Background2.png");
bgForPuzzle->setAnchorPoint(Point::ZERO);
bgForPuzzle->setPosition(Point::ZERO);
addChild(bgForPuzzle, ZOrder::BgForPuzzle);
}
auto userDefault=UserDefault::getInstance();
int value=userDefault->getIntegerForKey("back"); //find value for back if exist then it return that value else return 0
auto sprite = Sprite::create(value==0?"Background2.png":"Background1.png");
sprite->setPosition(100, 100);
this->addChild(sprite, 0);
When you want to change your background just put any value rather than 0
UserDefault::getInstance()->setIntegerForKey("back", 1);
I want to ask you guys to help me with creating keyframes in Max SDK C++.
What I've done:
Created a Controller Plugin
Inside the getValue function I've done my translations via code.
I also wrote the setValue function.
Which I think manages keyframes and stores the controllers position in a given time in a given keyframe. In this way I achieved to be able to set keys manually, but I really would like, to work with the Auto Key turned on in Max.
On the other hand, I can't see the freshly added keys values. So please help me, how could I add keyframes?
Many Thanks:
Banderas
void maxProject3::GetValue(TimeValue t, void *ptr, Interval &valid, GetSetMethod method)
{
Point3 p3OurAbsValue(0, 0, 0);
tomb[0]=0;
//These positions stores my data they are globals
XPosition += (accX);
YPosition += (accY);
ZPosition += (accZ);
p3OurAbsValue.x = XPosition;
p3OurAbsValue.y = YPosition;
p3OurAbsValue.z = ZPosition;
valid.Set(t,t+1); //This answer is only valid at the calling time.
MatrixCtrl->GetValue(t, &p3OurAbsValue.y, valid, CTRL_RELATIVE);
if (method == CTRL_ABSOLUTE)
{
Point3* p3InVal = (Point3*)ptr;
*p3InVal = p3OurAbsValue;
}
else // CTRL_RELATIVE
{
//We do our translations on a Matrix
Matrix3* m3InVal = (Matrix3*)ptr;
//m3InVal->PreTranslate(p3OurAbsValue);
m3InVal->PreRotateX(rotX);
m3InVal->PreRotateY(rotY);
m3InVal->PreRotateZ(rotZ);
}
}
int maxProject3::NumSubs() {
return 1;
}
Animatable* maxProject3::SubAnim(int n) {
return MatrixCtrl;
}
void maxProject3::SetValue(TimeValue t, void *ptr, int commit, GetSetMethod method)
{
Matrix3* m3InVal = (Matrix3*)ptr;
MatrixCtrl->AddNewKey(t, ADDKEY_SELECT);
MatrixCtrl->SetValue(t, &m3InVal, commit, CTRL_RELATIVE);
}
To turn on the Auto key mode try using AnimateOn() before your transformation. Also add AnimateOff() to turn off the auto key mode in the end.
I did it in one of my project to create material id animation using auto key mode.
/** Auto key on*/
AnimateOn();
/** Creating material id animation */
for(int mtl_id = 1; mtl_id <= num_sub_mtl; ++mtl_id, time += time_step)
{
mtl_modifier->GetParamBlock()->SetValue(MATMOD_MATID,time,mtl_id);
}
/** Auto key off*/
AnimateOff();
Also as a suggestion, use the max script listener to know whats happening when the animation is created using 3ds Max GUI. This will help you to recreate the animation using Max SDK.