Wednesday, April 22, 2015

Setting up a company

I've been both thinking about this and procrastinating for ages.

But now I need people to make MM good.


  • Artists, who can create FBX, VFX, animations and textures.
  • Designers who can bring levels to life.
  • Designers who can shape learning, can create dictionaries of gameplay and can hone the existing gameplay until its sharp.
  • Audio creators who can create a set of assets that bring the game to life.
  • Translators who can work in the many languages
  • Creative people


And to bring them into the fold they need structure.

  • A company umbrella providing a legal entity
  • Defined methods of wealth generation distribution
  • A team structure

They need to be instructed in MM's core aims, and find space within that to help us create an awesome product.

So I need to create a company, and find people to work in it, and money to pay the people if needed until MM is revenue producing.

Yikes!

Unreal Blueprints vs C++, my choice

When I started using unreal it was obvious that blueprints were very powerful. They are an enabler for people who can't code in C++ and a great way to data drive logic, avoiding code bloat if used correctly.

As a coder though its taken me a while to start feeling their power. I think there are several reasons for this:

  • I know C++, its a powerful tool, everything that you can do in blueprint (nearly) you can do in C++, and more.
  • My early use of blueprints got messy fast. Partly this is through not knowing how to use them, and partly because things like math expressions do not map well to blueprints.
  • The project I am working on is not a "normal" game. It involves more logic surrounding word associations and no shooting, or cool looking characters running around.
Early logic that I put into blueprints fairly quickly migrated back to C++ and everytime I did this it seemed to be for the better.

Now the core gameplay is up and running though I find blueprints start coming back into things. This is happening as I start pushing towards allowing content creators to make MM awesome. 

This means hooking up animations, level enclosures, particles effects.

To keep things sane I've adopted something similar to a object-view model. The C++ and some background data (dictionaries of words, basic logic paramaters for the different mode's we have) drive the gameplay logic and send events to blueprints.

Blueprints respond to these events however they like. They can reference whatever assets they like. They can tick in the background and be made as complicated as their designer wants.

Each section of a level in MM can now load a blueprint actor which can pull in all the cool stuff. Events are then sent to the blueprint actor using the awesome blueprint event binding system. Right now blueprints respond by adding particle effects and by animating skeleton that can query level progress through some simple data exposed to the blueprint actor.

Next up the blueprints will be allowed a little feedback, for instance they will be able to pause gameplay while they run an animation.

It'll be interesting to see where this ends. I'm happy with the idea of keeping logic within C++ with it's concise statements and amazing debugger, and to see where expanding blueprints ability to make things look great goes.

Overall I'm very happy with the way unreal has integrated C++ and blueprints but as a long time proponent of simple scripting languages I do wonder if there is a missing bit in the middle.

Perhaps this will help you with your initial approach to blueprints, perhaps it won't.


Does your vcpkgrsrv go crazy?

https://forums.unrealengine.com/showthread.php?55056-Visual-Studio-2013-Express-vcpkgsrv-exe-going-crazy

This is actually a problem with your intellisense settings. If you close those processes they just reopen.

Go to "Tools->Options->Text Editor->C/C++->Auto Tune Max Cached Translation Units" Set it to false

Now under the same place set "Max Cached Translation Units" to 2 since that's the lowest possible value.

That will limit VS to only launching 2 of those processes at a time instead of like 7 of them or something. Your horrible performance issues should now go away since all your RAM will stop being eaten up by intellisense.

Thank you! (Found setting under the intellisense Advanced tab).

Monday, March 23, 2015

UI

Every project I've worked on, big (I've worked on the biggest) or small (I'm working on the smallest) I end up as a UI programmer.

This is a field that is always underestimated. It's your user's first experience of the game and frustrating menus and interactions are going to drive them away in droves.

Working as a solo developer on a small scale project I'm finding that as much as 50% of my time is spent on UI.

I'm working on it right now.

Don't underestimate it.

That is all.

Paper2d driven by C++

I couldn't find much information online about this hence the post.

Wanting to layer 2d images behind 3d actors in Unreal I found myself unable to do so using the Canvas draw commands. This led me to investigate Paper2d as when I started looking for information on applying textures to static meshes paper2d development articles started popping up.

However while Paper2d provides some pretty slick looking 2d tools I couldn't find any documentation about how to create sprites from C++.

So here's what it takes:

#include "PaperSpriteActor.h"
void CreateTestSprite(UTexture *pTestTexture, UWorld *pWorld, AActor *pOwner)
{
APaperSpriteActor* spawnedSprite = pWorld->SpawnActorDeferred<APaperSpriteActor>(APaperSpriteActor::StaticClass(), FVector::ZeroVector, FRotator(0.0f, 0.0f, 90.0f), pOwner);
if (spawnedSprite)
{
FSpriteAssetInitParameters initParams;
initParams.SetTextureAndFill((UTexture2D*)pTestTexture);
UPaperSprite *pNewSprite = (UPaperSprite *)StaticConstructObject(UPaperSprite::StaticClass(), spawnedSprite);
pNewSprite->InitializeSprite(initParams);
spawnedSprite->GetRenderComponent()->SetMobility(EComponentMobility::Movable);
spawnedSprite->GetRenderComponent()->SetSprite(pNewSprite);
spawnedSprite->SetActorScale3D(FVector(200.0f, 200.0f, 200.0f));
spawnedSprite->OnConstruction(spawnedSprite->GetTransform());
spawnedSprite->FinishSpawning(spawnedSprite->GetTransform());
}
}

One other thing to note (and this is very early days in my use of the system) is that an initial test with a 600x600 source texture left me with a blobby looking very low res image, while a 128x128 seems to draw as expected.

Friday, January 23, 2015

Simple Bitset

As mentioned yesterday I was going to need to implement a bitset and would post it here when working. Below is the code.

Operators returning copies of a bitset are intentionally left out, the idea being these are expensive operations due to the memory allocations for the bit array. They could easily be implemented using the implemented Copy and Copy Constructor functions though if needed.

*NOTE* A lack of bounds checking in the functions. Could be implemented easily but left out in this v0.1 implementation.

Use any code posted on this blog freely but completely at your own risk, it will work within the parameters I have tested but may contain leaks or other obvious flaws include crashes, endless loops and any other coding issue you care to think of.

#pragma once

class LogicalBitset
{
unsigned int *m_Bits = 0;
int m_NumInts = 0;
int m_NumBits = 0;

public:
LogicalBitset()
{}

LogicalBitset(const LogicalBitset &rOther)
{
Copy(rOther);
}

~LogicalBitset()
{
delete m_Bits;
}

void Init(int iNumBitsNeeded)
{
delete m_Bits;
m_NumInts = (iNumBitsNeeded >> 5) + 1;
m_NumBits = iNumBitsNeeded;
m_Bits = new unsigned int[m_NumInts];
memset(m_Bits, 0, sizeof(m_Bits[0]) * m_NumInts);
}

void Copy(const LogicalBitset &rOther)
{
if (rOther.m_NumInts)
{
Init(rOther.m_NumBits);
for (int i = 0; i < m_NumInts; i++)
{
m_Bits[i] = rOther.m_Bits[i];
}
}
else
{
Reset();
}
}

void Reset()
{
delete m_Bits;
m_Bits = nullptr;
m_NumInts = 0;
m_NumBits = 0;
}

int GetNumBits() const
{
return m_NumBits;
}

void Resize(int neededBits)
{
//Grow only for now
if (neededBits > m_NumBits)
{
int neededInts = (neededBits >> 5) + 1;
if (neededInts > m_NumInts)
{
//Copy old data across to new container
unsigned int *pIntArray = new unsigned int[neededInts];
for (int i = 0; i < m_NumInts; i++)
{
pIntArray[i] = m_Bits[i];
}
delete m_Bits;
pIntArray[m_NumInts] = 0;
m_Bits = pIntArray;
m_NumInts = neededInts;
}
m_NumBits = neededBits;
}
}

void AddBit(bool bValue)
{
int neededBits = m_NumBits+1;
int neededInts = (neededBits >> 5) + 1;
if (neededInts > m_NumInts)
{
//Copy old data across to new container
unsigned int *pIntArray = new unsigned int[neededInts];
for (int i = 0; i < m_NumInts; i++)
{
pIntArray[i] = m_Bits[i];
}
delete m_Bits;
pIntArray[m_NumInts] = 0;
m_Bits = pIntArray;
m_NumInts = neededInts;
}
m_NumBits = neededBits;
SetBit(m_NumBits - 1, bValue);
}

bool IsSet() const
{
return m_NumInts > 0;
}

void SetBit(int iIndex, bool bValue)
{
int iInt = iIndex >> 5;
int iValue = m_Bits[iInt];
int iBit = iIndex & 31;
int iBitMask = 1 << iBit;
m_Bits[iInt] = (iValue & (~iBitMask)) | (bValue ? iBitMask : 0);
}

bool GetBit(int iIndex)
{
int iInt = iIndex >> 5;
int iBit = iIndex & 31;
return (m_Bits[iInt] & (1 << iBit)) != 0;
}

bool operator==(const LogicalBitset &rOther) const
{
if (m_NumInts != rOther.m_NumBits)
return false;

for (int i = 0; i < m_NumInts; i++)
{
if (m_Bits[i] != rOther.m_Bits[i])
return false;
}
return true;
}

void operator=(const LogicalBitset &rOther)
{
Copy(rOther);
}

void Zero()
{
for (int i = 0; i < m_NumInts; i++)
{
m_Bits[i] = 0;
}
}

bool IsNonZero() const
{
for (int i = 0; i < m_NumInts; i++)
{
if (m_Bits[i] != 0)
return true;
}
return false;
}

bool ContainsSomeBits(const LogicalBitset &rOther) const
{
for (int i = 0; i < m_NumInts; i++)
{
if (m_Bits[i] & rOther.m_Bits[i])
return true;
}
return false;
}

bool ContainsAllBits(const LogicalBitset &rOther) const
{
for (int i = 0; i < m_NumInts; i++)
{
const unsigned int iOtherBits = rOther.m_Bits[i];
if ((m_Bits[i] & iOtherBits) != iOtherBits)
return false;
}
return true;
}
};

Thursday, January 22, 2015

VS Community profiling

Some notes jotted down while I was playing with this profiler for the first time.

Profiling

  • Open the "Performance Explorer"
  • Right click on a project - "Start profiling"
  • If asked to upgrade your profile, say yes
  • Switch of sampling on your target until at the point you want to profile.
  • Once you are finished look at the .vsp file, it may take some processing to show up
  • You need to sample long enough to get some moderaly accurate samples
  • Current View (top selection box): Modules is very useful in Unreal as you might want to differentiate between your code and engine code.
  • Sample for long enough to get > 1 samples in functions you care about (or enough in functions you don't to eliminate the need to care). More samples makes your game perform slower!
  • If you don't have "Collect Samples" ticked at launch it will complain about not having any executables selected for profiling, that's okay.
  • I've found that sometimes the application doesn't launch through the performance explorer, in which case you can simply launch normally and "attach"
  • When you stop profiling and first see the result you see a time line in seconds - you can select a section of this to generate data from, by default the whole time is used.
  • On that same summary page - top rightish, there is an option to "Show Just My Code", this is very helpful to getting to the bits you are working on.


Unreal editor - finding your update code - look here:

UE4Editor-UnrealEd.dll
-FEngineLoop::Tick
--GuardedMain
---WinMain
----_tmainCRTStartup
-----UE4Editor.exe
------My update functions should be here