Wednesday, 2 December 2015

Session 11

Operations!
One example of an operation is x == y. This is the equality operation
It compares one thing to another (x is equal to y), if it was a single = it'd be assigning the value instead of comparing

Function pointers
A function identifier is a constant pointer to a function, eg:
void run(); //the brackets are the dereference bit

The address of a function can be stored, eg:
int(*anyName)(Health&);
anyName(gremlin.getHealth());

The brackets specify that you want the function's address and not just a generic pointer address
Storing pointer functions - implicit means you don't specify that the pointer is a function pointer, it is only implied.
Explicit function pointer storing requires that you Do specify (using (*x), where x is the name of the function)
It is possible to pass function pointers to different functions
But why? You can compare, by adding the function pointer to the function signature

Decltype evaluates type of an expression to cheat our declaration of function pointers as a time
Decltype is like the auto keyword; saves time and effort (looks a bit neater too for longer declarations)
Auto saves having to write: bool (*functionPointer)(int x, int y)
Can use function pointers when making a factory

Static GameObject* createObject() {return new PlayingCard;}
is the same as:
std::map<std::string, GameObject*(*)() map;

State Machine - if all action-handling functions have the same signature, you can use function pointers for the input
Functor - a function 'wrapped up' as a class. Can use, for example, a multiplication class as if it were a function

Session 10

Observer
An observer defines a one-to-many dependency between objects so that when one object updates, anything attached to that object updates (and reacts to it) too automatically
Allows a reduce in the level of complexity - easier to look at, saves time etc.
Can set an event that tells everything that happens (eg a player dies), this saves manual checking as anything that needs to know about the player dying will automatically know
The observed class is also known as the subject

example syntax:
observable subject;
subject.addObserver(observer); //to add an observer

Performance - be aware there is some overheard for iterating through with observers
However, instead of checking continuously, something can be made to run Only when it sees an event to counter that
When an event plays, the thread pauses and observers update functions
Add observers during compile to reduce lag during runtime

Component Pattern
Allows a single entity to span multiple domains (aka systems) without having to couple those domains
('Multiple domains' can refer to rendering, update, input etc)
Each domain can become a component
For example, a gameobject knows it has multiple components, but it doesn't have to know what they actually do
These components don't have to be coupled together
There is no need for class hierarchy when using composition
(for reference, class hierarchy is this kind of thing):

Type Patterns
These allow for flexible creation of new classes
Usually enemy classes for example are very similar so instead of multiple sub-classes, type can be used
Each enemy has a breed which holds its health, damage, etc
Behaviour can be read from a text file if the breed is complex, this would save coding space but isn't really necessary

Friday, 20 November 2015

Session 8

Do not use windows.h
Windows.h bloats codespace (possible code duplication, slower performance etc)
You also lose portability using windows.h as it will only work with Windows systems
Also avoid using console commands like system(" ")
Instead, to sleep (pause), use: std::this_thread::sleep_for(std::chrono::milliseconds(frameWait));
In C++14 and higher, literals can be used if you #include chronos, you can write 5s for 5 seconds, 10ms for 10 milliseconds, etc.
Polling for input also - getting key input

Clear screen - can't use system commands so an alternative is to simply print enough new lines to replace all onscreen.
#ifndef is a pre-processing statement, happens before any compilation
If using C++ 11 or higher there is a C++ specific clear screen function that can be used
As well as a Visual Studio-specific one...
#ifndef _MSC_VER to use Visual Studio version
must #endif

Auto - the auto keyword can be used to save time.
Auto deduces the correct variable type, like float/int/char etc based on what follows.
For example, a number with a decimal point should be classed as a float, if auto is used
Only safe to use when you are certain of what the computer will treat the variable as

example syntax of using auto in a for loop:
for(auto& player : players)
{
//for every player in players
}

Weak pointers can only be created from shared pointers
Weak pointers cannot influence when an item gets destroyed, hence 'weak'
Locking a weak pointer creates a shared version for that line (temporarily)

Big O notation
O = order
Complexity refers to how the numbers of inputs impact the processing time
The order is the rate of growth
T(n) = O(n^2) where T is time, and grows in the order of n^2, this is an exponential growth
An order of magnitude lets us see the scale or magnitude of the algorithm in a nice, easy to follow visual example - no need to see the numbers explicitly
Given x number, how does that impact processing time

Algorithm - sort of like a recipe, it is a set of rules that govern a series of calculations or problem-solving solutions
Every line, operation or formation can be considered an algorithm as it tells the computer what to do
Algorithms are unambiguous, very specific

In a constant expression, time taken will never change
In a linear expression, time taken increasing with more inputs can be represented using a straight line
Polynomial expressions show a steep curve in growth
Still all just a visual representation without explicit values
Logarithmic expressions are the opposite of polynomial; diminishing returns (smaller difference between inputs, the more inputs there are)

Sunday, 8 November 2015

Session 7

Vectors and Pointers

A vector is a container, you can put pointers in vectors
Pointers are stored contiguously but the memory it points to is on the heap, allocated by default
The memory that is pointed to is thus not guaranteed to be contiguous
If a vector pointer points to some information that was manually allocated, it will have to be manually deallocated too

When you don't want to share copies of objects, arrays or pointers are good
If you do copy, a change will only affect one and it will cause slowdown
Push-back is used to add memory to the end of a container
Must deallocate the pointers before clearing the vector
Unique pointers, however, will deallocate themselves, but any information can only have 1 unique pointer pointing to it
level3.push-back(RoomUniPointer((new _____)) example unique pointer declaration syntax

Using shared pointers, use std::make_shared(room x)
Shared pointers guarantee that the pointers will stay valid even if the container is cleared
Can use a weak pointer to make a cache that can't be cleared
Weak pointers must be connected to be used

Associative containers are related to what is in them
For example, a container of strings would then have the properties of a string
A container of strings could be sorted alphabetically
It can also be searched by name, as opposed to being searched by its number
Until now, a container's order was only determined by what order the items were added

A set is like a container but it can only hold unique 'keys'
Sets are also in a specific order
The value of the key also determines how unique ?
Sorting in a set uses a less-than comparison (lowest first)
Sorting in a vector is slower, but it still works
Vector sorting has to go through every item to make sure it is in the right place, and this must be done every time a new item is added too
Iteration is faster in a vector though as it is simply added to the end
Sets need to know only what is to the left and right of the current item, making for faster sorting
Sets also do not have to shift all items left or right when an item is added or removed
In a set, the value is the key, which is also the element

Find:set is a logarithmic search, whereas find:std is a linear search
find_if requires a boolean predicate; a yes or no state
Associative containers cannot do this
In a map, the lookup key is separate from the value stores in the array
Pair - look up first, return second. A string is usually the key
This has the same overheard as a set

Multi-sets can have duplicates, but they are the same as a set otherwise
Same for multi-maps
Useful when caching where hash might be duplicated
No real reason to use...

Monday, 2 November 2015

Session 6

Shared pointers - access same memory with different pointers
A weak pointer checks if the data that a shared pointer points to is valid

Casting is making a variable act like a different type of variable (for one single operation), for example, you can tell the computer to interpret a number as a char instead. The char output should be the equivalent of the number... based on ASCII value?
Implicit (implied) conversions are automatically performed when a value is copied to a compatible type

Libraries are good because they're made by the experts; saves time and effort

When a vector is created, 3 pointers are also made - a beginning, end and last used. Example: array of size 10, 1-7 are in use. There will be pointers to 1, 10 and 7 as beginning end and last (in that order).
Size vs capacity - the size is the number of objects, whereas capacity is how much space there is for objects altogether
Consider using vectors instead of arrays as they are fast and efficient, but similar to use (ease)

A contiguous memory block benefits caching and prevents fragmentation
An iterator is any object that points to an element in a container, like ++ and -- (increment and decrement)

Erase-remove process, must do both. Remove-erase is the correct order...
Linked list - loads of nodes that link to each other
Linked list can go backwards and forwards
Memory is allocated node by node, and can be assigned anywhere but if it isn't contiguous it might end up going to RAM (which is slower)
As long as there are pointers to the next item, that item can be anything at all
Removal - nodes removed have their memory location automatically deallocated
Easy to add or remove new items by breaking chains within linked lists
Link lists are good for performance as there is no overhead other than the allocation/deallocation
Adding and removing new items is easy because other items don't have to be shifted left or right

Double-ended containers can be expanded or contracted at either end
They are similar to vectors but items may be modified at the front and end
Efficient for adding/removing new items
Memory is not guaranteed to be contiguous.

Friday, 16 October 2015

Session 4

Recursion is what it is called when a function calls itself. Like a paradox
If the base case (is = 0 etc) doesn't stop it will last forever!
If it is on the stack it will overflow and cause major problems at runtime.
Recursive calls can slow down memory - if they are endless, there could be millions of things happening at the same time... even if you have enough space for them all

A continuous (contiguous - in a row) block of memory is required for a static array
Static arrays are a fixed size, hence static (which means lacking movement, change etc)
Due to this, there might be memory allocated that is never used...

Dynamic arrays also require contiguous memory blocks but the size is not fixed - the size can change as required, so as not to waste any memory, and to never have too high a quantity
example array syntax: Item inventory [2] [5]; this is a table with 2 rows and 5 columns

Dynamic arrays should be constant (const) referenced if variable is not going to be changed
Cannot have null references and they must be initialised when created
And only return references and pointers when you know the data is still valid.



Friday, 9 October 2015

Session 3

Ship
+turn ()
+move()
+shoot()

-rotation:float
-momentum:float
-thrust:float

(example of UML diagram)

Looked for common functionality
Looked at how the objects inherit
All gameobjects have potential for animation
Polymorphism - one version of attack (boss for example) can be different if virtual is used. Attack would also be used by a regular monster if boss is also a monster
Do not override non-virtual stuff!

#ifndef (headername)
#define (headername)
#endif
or use
#pragma once

these make sure headers and such are only included once during compilation

Forward declaration tells the compiler the identifier's size and data type; this is all the compiler needs to run
Forward declaration is a performance saver (less hardware intensive)

Static memory - memory is allocated but once it drops off it deallocates.
Cleanup is automatic and this prevents memory leak
Static things need to know their quantity though...
Memory gets popped off the stack after its space, first in last out
Dynamic memory allocation is separate from spaces so it is up to you (me!) to point to it and deallocate... otherwise problems

Thursday, 1 October 2015

Session 2

Use initialiser list for constructor
Don't call virtual functions from constructors
Construction happens FIRST - variables don't exist yet!
Constructors can be chained - eg call another constructor from default
We should only see virtual variables in public
example of syntax: class rock: (is a) public IsAGameObject

Composition - model an object: door has handle, but door is not handle
Private inheritance implemented as you may have a base class you want to use
Virtual variables are determined at runtime - dynamic override can only be used on virtual variables
Diamond problem is objects inherit from a gameobject, but then another object inherits from both of those

Use virtual (pointer) to make sure object is not replicated
Using virtual may be more hardware intensive...
The most derived (original source?) class initialises
Using = delete can help to stop other classes inheriting or calling the object
Binding is designating memory addresses. Static is early, dynamic is late

Tuesday, 22 September 2015

Session 1

Learned about the importance of protecting code, and how to access it even if it is.

Pure Virtual functions allow you to set up an interface but you must initialise them with every subclass.

They can be helpful to use a function before the gameobject even knows what the identifier value is.