FolkeLogo

Welcome to my Tools section.


Here are some minor tool projects I have been working on:

Decals:


  • Description: A decal system I made during a tool course at Futuregames. Each ball adds a patch of its own color wherever it bounces. Each patch is the same render call.

         (The gif experiences some minor glitches due to recording problems)


  • Made in: Unity.


  • Time: 1 Week.


          		
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SinglePooling : MonoBehaviour
{
    public Material[] SphereMaterials;
    public GameObject Ball;
    GameObject[] Spheres;
    public Transform spawnPos;
    Vector3 RandomForce;
    void Start()
    {
        Spheres = new GameObject[SphereMaterials.Length];
        for (int i = 0; i < SphereMaterials.Length; i++)
        {

            Spheres[i] = GameObject.Instantiate(Ball);  
            Spheres[i].GetComponent<MeshRenderer>().material = SphereMaterials[i];
            Spheres[i].SetActive(false);
        }
    }
    public void ClickyClicky()
    {
        RandomForce = new Vector3(Random.Range(-1f, 1f), 0, Random.Range(-1f, 1f)) * 1000f;

        for (int i = 0; i < Spheres.Length; i++)
        {
            if(Spheres[i].activeInHierarchy == false)
            {
                Spheres[i].SetActive(true);
                Spheres[i].transform.position = spawnPos.position;
                StartCoroutine(waitforforce(Spheres[i], RandomForce));
                break;
            }
        }
    }
    IEnumerator waitforforce(GameObject forcethis, Vector3 Force)
    {
        yield return new WaitForSeconds(0.1f);
        forcethis.GetComponent<BallBounce>().Bounce(Force);
    }
}
        
	
          		
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BallBounce : MonoBehaviour
{
    Decal decalSpawner;
    Rigidbody rb;
    void Start()
    {
        decalSpawner = GetComponent<Decal>();
        rb = GetComponent<Rigidbody>();
        StartCoroutine(waitforforce());
    }
    IEnumerator waitforforce()
    {
        Vector3 randomStart = new Vector3(Random.Range(-1f, 1), 0, Random.Range(-1f, 1));
        yield return new WaitForSeconds(0.1f);
        Bounce(randomStart * 1000f);
    }
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "WallArea")
        {
            Quaternion Qua = Quaternion.FromToRotation(Vector3.forward, collision.GetContact(0).normal);

            Vector3 hitLocation = new Vector3(
                collision.GetContact(0).point.x + (collision.GetContact(0).normal.x * 0.01f),
                collision.GetContact(0).point.y + (collision.GetContact(0).normal.y * 0.01f),
                collision.GetContact(0).point.z + (collision.GetContact(0).normal.z * 0.01f));

            decalSpawner.DrawDecal(hitLocation, Qua);
        }
    }
    public void Bounce(Vector3 direction)
    {
        rb.AddForce(direction);
    }
}

        
	
          		
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Decal : MonoBehaviour
{
    Material decalMaterial;
    Mesh decalMesh;

    private Vector3[] newVertices =
        {
        new Vector3(0,0,0),
        new Vector3(1,0,0),
        new Vector3(1,1,0),
        new Vector3(0,1,0)
            };
    private int[] newTriangles = { 0, 1, 3, 1,2,3 };
    private const int indexsize = 1000;
    private int currIndex = 0;
    private Matrix4x4[] matrixList = new Matrix4x4[indexsize];

    void Start()
    {
        decalMaterial = GetComponent<MeshRenderer>().material;
        decalMesh = new Mesh();
        decalMesh.vertices = newVertices;
        decalMesh.triangles = newTriangles;
    }
    void Update()
    {
            Graphics.DrawMeshInstanced(decalMesh, 0, decalMaterial, matrixList);
    }
    public void DrawDecal(Vector3 position, Quaternion rotation)
    {
        matrixList[currIndex].SetTRS(position, rotation, Vector3.one);
        currIndex = (currIndex + 1) % matrixList.Length;
    }
}
        
	

Linked List:


  • Description: Maybe not much of a tool as it is a sorting algorithm. The red squares shown on the picture is the tail from the pink square. Each square has a link to the square behind them, telling the square each tick (2 tick every second) where the next position is going to be. Every time the head pick up food (blue square), a new tail spawn and the tick rate speed up. 


  • Made in: Unreal Engine.


  • Time: ~1 Week.


          		
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "SubclassOf.h"
#include "SnakeTail.h"
#include "Snakey.generated.h"

class ASnakeTail;
class UStaticMeshComponent;
class UBoxComponent;

UCLASS()
class SNAKE_API ASnakey : public APawn
{
	GENERATED_BODY()
public:

	ASnakey();

protected:
	virtual void BeginPlay() override;

public:
	virtual void Tick(float DeltaTime) override;
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
	void HandleMovement(float delta);
	void TurnRight();
	void TurnLeft();
	void SpawnTail();
	UFUNCTION()
		void OnCollectiveOverlapp(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);
	UPROPERTY()
		float MaxCD = 0.5f;
	UPROPERTY()
		float Cooldown;
	UPROPERTY(EditDefaultsOnly)
		TSubclassOf<ASnakeTail> MySnakeTail;
	UPROPERTY()
		FVector LastPos;
	UPROPERTY(EditDefaultsOnly)
		UBoxComponent* MyBox;
	UPROPERTY()
		ASnakeTail* NextTail;
	UPROPERTY(EditDefaultsOnly)
		UStaticMeshComponent* MyMesh;
};
        
	
          		
#include "Snakey.h"
#include "Components/InputComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Components/BoxComponent.h"
#include "ConstructorHelpers.h"
#include "Engine/World.h"
#include "Collectible.h"
#include "Components/StaticMeshComponent.h"
#include "Kismet/GameplayStatics.h"

ASnakey::ASnakey()
{
	PrimaryActorTick.bCanEverTick = true;
	MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("HEAD"));
	MyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MESH"));
	RootComponent = MyBox;
	MyMesh->SetCollisionProfileName(TEXT("OverlapAll"));
	MyMesh->SetupAttachment(MyBox);
	MyMesh->OnComponentBeginOverlap.AddDynamic(this, &ASnakey::OnCollectiveOverlapp);
}
void ASnakey::BeginPlay()
{
	Super::BeginPlay();
	Cooldown = MaxCD;
	MyMesh->SetWorldScale3D(MyBox->GetComponentScale());
}
void ASnakey::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	HandleMovement(DeltaTime);
}
void ASnakey::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	PlayerInputComponent->BindAction("TurnRight", IE_Pressed, this, &ASnakey::TurnRight);
	PlayerInputComponent->BindAction("TurnLeft", IE_Pressed, this, &ASnakey::TurnLeft);
}

void ASnakey::HandleMovement(float delta)
{
	if (Cooldown > 0)
		Cooldown -= delta;
	if (Cooldown <= 0)
	{
		LastPos = GetActorLocation();
		this->AddActorWorldOffset(this->GetActorForwardVector() * 100);
		if (NextTail != nullptr)
			NextTail->Move(LastPos);
		Cooldown = MaxCD;
	}
}
void ASnakey::TurnRight()
{
	this->AddActorWorldRotation(FRotator(0, 90, 0));
}

void ASnakey::TurnLeft()
{
	this->AddActorWorldRotation(FRotator(0, -90, 0));
}

void ASnakey::SpawnTail()
{
	if (NextTail != nullptr)
		NextTail->SpawnTail();
	else
		NextTail = GetWorld()->SpawnActor<ASnakeTail>(MySnakeTail, LastPos, FRotator(0));
}

void ASnakey::OnCollectiveOverlapp(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
{
	if (OtherActor != NextTail && !OtherActor->IsA<ACollectible>() && OtherActor->GetName() != "SpectatorPawn_0" && OtherActor->GetName() != "BP_Snakey_C_0")
		UGameplayStatics::OpenLevel(GetWorld(), "?Restart");
}

        
	
          		
  
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SnakeTail.generated.h"

class UBoxComponent;
class UStaticMeshComponent;

UCLASS()
class SNAKE_API ASnakeTail : public AActor
{
	GENERATED_BODY()
public:
	ASnakeTail();
	UFUNCTION()
		void SpawnTail();
	UFUNCTION()
		void Move(FVector Position);
	UPROPERTY()
		ASnakeTail* SnakeTail;
	UPROPERTY(EditAnywhere)
		UStaticMeshComponent* MyMesh;
	UPROPERTY(EditAnywhere)
		UBoxComponent* MyBox;
};
        
	
          		

#include "SnakeTail.h"
#include "Components/BoxComponent.h"
#include "Components/StaticMeshComponent.h"
#include "ConstructorHelpers.h"
#include "Engine/World.h"
#include "Class.h"

ASnakeTail::ASnakeTail()
{
	PrimaryActorTick.bCanEverTick = true;
	MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("Tail"));
	RootComponent = MyBox;
	MyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
	MyMesh->SetupAttachment(RootComponent);
	SnakeTail = nullptr;
}

void ASnakeTail::SpawnTail()
{
	if (SnakeTail != nullptr)
		SnakeTail->SpawnTail();
	else
		SnakeTail = GetWorld()->SpawnActor<ASnakeTail>(GetClass(), GetActorLocation(), FRotator(0));
}

void ASnakeTail::Move(FVector Position)
{
	if (SnakeTail != nullptr)
		SnakeTail->Move(GetActorLocation());
	this->SetActorLocation(Position);
}
        
	

(more coming)