|
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. |
|
|
|
#include "ItemSample.h" |
|
#include "ItemSampleCharacter.h" |
|
#include "ItemSampleProjectile.h" |
|
#include "Animation/AnimInstance.h" |
|
#include "UsableItem.h" |
|
#include "GameFramework/InputSettings.h" |
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LogFPChar, Warning, All); |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// AItemSampleCharacter |
|
|
|
AItemSampleCharacter::AItemSampleCharacter() |
|
{ |
|
// Set size for collision capsule |
|
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f); |
|
|
|
// set our turn rates for input |
|
BaseTurnRate = 45.f; |
|
BaseLookUpRate = 45.f; |
|
|
|
// Create a CameraComponent |
|
FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera")); |
|
FirstPersonCameraComponent->AttachParent = GetCapsuleComponent(); |
|
FirstPersonCameraComponent->RelativeLocation = FVector(0, 0, 64.f); // Position the camera |
|
FirstPersonCameraComponent->bUsePawnControlRotation = true; |
|
|
|
// Default offset from the character location for projectiles to spawn |
|
GunOffset = FVector(100.0f, 30.0f, 10.0f); |
|
|
|
// Create a mesh component that will be used when being viewed from a '1st person' view (when controlling this pawn) |
|
Mesh1P = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("CharacterMesh1P")); |
|
Mesh1P->SetOnlyOwnerSee(true); // only the owning player will see this mesh |
|
Mesh1P->AttachParent = FirstPersonCameraComponent; |
|
Mesh1P->RelativeLocation = FVector(0.f, 0.f, -150.f); |
|
Mesh1P->bCastDynamicShadow = false; |
|
Mesh1P->CastShadow = false; |
|
|
|
//Included in 4.7, needs to be added in 4.8 |
|
PrimaryActorTick.bCanEverTick = true; |
|
|
|
// Note: The ProjectileClass and the skeletal mesh/anim blueprints for Mesh1P are set in the |
|
// derived blueprint asset named MyCharacter (to avoid direct content references in C++) |
|
} |
|
|
|
// Called every frame -- Included in 4.7, needs to be added in 4.8 |
|
void AItemSampleCharacter::Tick(float DeltaTime) |
|
{ |
|
Super::Tick(DeltaTime); |
|
|
|
AUsableItem* itemSeen = GetItemFocus(); |
|
static AUsableItem* oldFocus = NULL; |
|
|
|
oldFocus = ApplyPostProcessing(itemSeen, oldFocus); |
|
|
|
} |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// Input |
|
|
|
void AItemSampleCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent) |
|
{ |
|
// set up gameplay key bindings |
|
check(InputComponent); |
|
|
|
InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump); |
|
InputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping); |
|
|
|
InputComponent->BindAction("Take", IE_Pressed, this, &AItemSampleCharacter::Use); |
|
|
|
//InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &AItemSampleCharacter::TouchStarted); |
|
if( EnableTouchscreenMovement(InputComponent) == false ) |
|
{ |
|
InputComponent->BindAction("Fire", IE_Pressed, this, &AItemSampleCharacter::OnFire); |
|
} |
|
|
|
InputComponent->BindAxis("MoveForward", this, &AItemSampleCharacter::MoveForward); |
|
InputComponent->BindAxis("MoveRight", this, &AItemSampleCharacter::MoveRight); |
|
|
|
// We have 2 versions of the rotation bindings to handle different kinds of devices differently |
|
// "turn" handles devices that provide an absolute delta, such as a mouse. |
|
// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick |
|
InputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput); |
|
InputComponent->BindAxis("TurnRate", this, &AItemSampleCharacter::TurnAtRate); |
|
InputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput); |
|
InputComponent->BindAxis("LookUpRate", this, &AItemSampleCharacter::LookUpAtRate); |
|
} |
|
|
|
void AItemSampleCharacter::Use(){ |
|
if (GetItemFocus()){ |
|
GetItemFocus()->GetStaticMeshComponent()->DestroyComponent(); |
|
} |
|
|
|
} |
|
|
|
void AItemSampleCharacter::OnFire() |
|
{ |
|
// try and fire a projectile |
|
if (ProjectileClass != NULL) |
|
{ |
|
const FRotator SpawnRotation = GetControlRotation(); |
|
// MuzzleOffset is in camera space, so transform it to world space before offsetting from the character location to find the final muzzle position |
|
const FVector SpawnLocation = GetActorLocation() + SpawnRotation.RotateVector(GunOffset); |
|
|
|
UWorld* const World = GetWorld(); |
|
if (World != NULL) |
|
{ |
|
// spawn the projectile at the muzzle |
|
World->SpawnActor<AItemSampleProjectile>(ProjectileClass, SpawnLocation, SpawnRotation); |
|
} |
|
} |
|
|
|
// try and play the sound if specified |
|
if (FireSound != NULL) |
|
{ |
|
UGameplayStatics::PlaySoundAtLocation(this, FireSound, GetActorLocation()); |
|
} |
|
|
|
// try and play a firing animation if specified |
|
if(FireAnimation != NULL) |
|
{ |
|
// Get the animation object for the arms mesh |
|
UAnimInstance* AnimInstance = Mesh1P->GetAnimInstance(); |
|
if(AnimInstance != NULL) |
|
{ |
|
AnimInstance->Montage_Play(FireAnimation, 1.f); |
|
} |
|
} |
|
|
|
} |
|
|
|
void AItemSampleCharacter::BeginTouch(const ETouchIndex::Type FingerIndex, const FVector Location) |
|
{ |
|
if( TouchItem.bIsPressed == true ) |
|
{ |
|
return; |
|
} |
|
TouchItem.bIsPressed = true; |
|
TouchItem.FingerIndex = FingerIndex; |
|
TouchItem.Location = Location; |
|
TouchItem.bMoved = false; |
|
} |
|
|
|
void AItemSampleCharacter::EndTouch(const ETouchIndex::Type FingerIndex, const FVector Location) |
|
{ |
|
if (TouchItem.bIsPressed == false) |
|
{ |
|
return; |
|
} |
|
if( ( FingerIndex == TouchItem.FingerIndex ) && (TouchItem.bMoved == false) ) |
|
{ |
|
OnFire(); |
|
} |
|
TouchItem.bIsPressed = false; |
|
} |
|
|
|
void AItemSampleCharacter::TouchUpdate(const ETouchIndex::Type FingerIndex, const FVector Location) |
|
{ |
|
if ((TouchItem.bIsPressed == true) && ( TouchItem.FingerIndex==FingerIndex)) |
|
{ |
|
if (TouchItem.bIsPressed) |
|
{ |
|
if (GetWorld() != nullptr) |
|
{ |
|
UGameViewportClient* ViewportClient = GetWorld()->GetGameViewport(); |
|
if (ViewportClient != nullptr) |
|
{ |
|
FVector MoveDelta = Location - TouchItem.Location; |
|
FVector2D ScreenSize; |
|
ViewportClient->GetViewportSize(ScreenSize); |
|
FVector2D ScaledDelta = FVector2D( MoveDelta.X, MoveDelta.Y) / ScreenSize; |
|
if (ScaledDelta.X != 0.0f) |
|
{ |
|
TouchItem.bMoved = true; |
|
float Value = ScaledDelta.X * BaseTurnRate; |
|
AddControllerYawInput(Value); |
|
} |
|
if (ScaledDelta.Y != 0.0f) |
|
{ |
|
TouchItem.bMoved = true; |
|
float Value = ScaledDelta.Y* BaseTurnRate; |
|
AddControllerPitchInput(Value); |
|
} |
|
TouchItem.Location = Location; |
|
} |
|
TouchItem.Location = Location; |
|
} |
|
} |
|
} |
|
} |
|
|
|
void AItemSampleCharacter::MoveForward(float Value) |
|
{ |
|
if (Value != 0.0f) |
|
{ |
|
// add movement in that direction |
|
AddMovementInput(GetActorForwardVector(), Value); |
|
} |
|
} |
|
|
|
void AItemSampleCharacter::MoveRight(float Value) |
|
{ |
|
if (Value != 0.0f) |
|
{ |
|
// add movement in that direction |
|
AddMovementInput(GetActorRightVector(), Value); |
|
} |
|
} |
|
|
|
void AItemSampleCharacter::TurnAtRate(float Rate) |
|
{ |
|
// calculate delta for this frame from the rate information |
|
AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds()); |
|
} |
|
|
|
void AItemSampleCharacter::LookUpAtRate(float Rate) |
|
{ |
|
// calculate delta for this frame from the rate information |
|
AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds()); |
|
} |
|
|
|
bool AItemSampleCharacter::EnableTouchscreenMovement(class UInputComponent* InputComponent) |
|
{ |
|
bool bResult = false; |
|
if(FPlatformMisc::GetUseVirtualJoysticks() || GetDefault<UInputSettings>()->bUseMouseForTouch ) |
|
{ |
|
bResult = true; |
|
InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &AItemSampleCharacter::BeginTouch); |
|
InputComponent->BindTouch(EInputEvent::IE_Released, this, &AItemSampleCharacter::EndTouch); |
|
InputComponent->BindTouch(EInputEvent::IE_Repeat, this, &AItemSampleCharacter::TouchUpdate); |
|
} |
|
return bResult; |
|
} |
|
|
|
AUsableItem* AItemSampleCharacter::ApplyPostProcessing(AUsableItem* itemSeen, AUsableItem* oldFocus){ |
|
if (itemSeen){ |
|
// An item is currently being looked at |
|
if (itemSeen == oldFocus || oldFocus == NULL){ |
|
//The item being looked at is the same as the one on the last tick |
|
UStaticMeshComponent* mesh = itemSeen->GetStaticMeshComponent(); |
|
mesh->SetRenderCustomDepth(true); |
|
|
|
} |
|
else if (oldFocus != NULL){ |
|
// An item is being looked at and the old focus was not null (and not the same as the one on the last tick) |
|
UStaticMeshComponent* mesh = itemSeen->GetStaticMeshComponent(); |
|
mesh->SetRenderCustomDepth(true); |
|
|
|
UStaticMeshComponent* oldMesh = oldFocus->GetStaticMeshComponent(); |
|
oldMesh->SetRenderCustomDepth(false); |
|
} |
|
|
|
return oldFocus = itemSeen; |
|
} |
|
else{ |
|
// No item currectly being looked at |
|
if (oldFocus != NULL){ |
|
//An item was looked at last tick but isn't being looked at anymore |
|
UStaticMeshComponent* mesh = oldFocus->GetStaticMeshComponent(); |
|
mesh->SetRenderCustomDepth(false); |
|
} |
|
|
|
return oldFocus = NULL; |
|
} |
|
|
|
} |
|
|
|
AUsableItem* AItemSampleCharacter::GetItemFocus(){ |
|
// Attempt to use Raycasts to view an object and echo it back |
|
FVector CameraLocation; |
|
FRotator CameraRotation; |
|
|
|
Controller->GetPlayerViewPoint(CameraLocation, CameraRotation); |
|
const FVector StartTrace = CameraLocation; |
|
const FVector Direction = CameraRotation.Vector(); |
|
const FVector EndTrace = StartTrace + Direction * 300; //where 300 is the distance it checks |
|
|
|
FCollisionQueryParams TraceParams(FName(TEXT("")), true, this); |
|
TraceParams.bTraceAsyncScene = true; |
|
TraceParams.bReturnPhysicalMaterial = true; |
|
|
|
FHitResult Hit(ForceInit); |
|
GetWorld()->LineTraceSingleByChannel(Hit, StartTrace, EndTrace, COLLISION_VIEW, TraceParams); |
|
|
|
return Cast<AUsableItem>(Hit.GetActor()); |
|
|
|
} |