Noob learns to code in 3 months

The Partridge Family were neither partridges nor a family. Discuss.
User avatar
Yumtard
Posts: 575
Joined: January 19th, 2017, 10:28 pm
Location: Idiot from northern Europe

Re: Noob learns to code in 3 months

Post by Yumtard » September 4th, 2017, 9:45 pm

Finished first programming assignment of the course.
The assignment was to write a combat simulator.

Assignment:
Spoiler:
main

Code: Select all

#include "Character.h"
#include "Weapon.h"
#pragma once

//Displays a message for when the combat is over
void Summary(Character& winner, Character& loser)
{
	std::cout << loser.GetName() << " lost." << std::endl;
	std::cout << winner.GetName() << " has " << winner.GetHealth() << " HP left." << std::endl;
}

int main()
{
	//Variables
	Weapon revolver(35, 70, 6, 1.5f, 0.5f);
	Weapon scrapGun(20, 255, 4, 1.5f, 1.0f);
	Character mcCree("McCree", 200, revolver);
	Character roadHog("RoadHog", 600, scrapGun, 30.0f, true);
	const float deltaTime = 0.1f;
	bool running = true;

	mcCree.SetOpponent(&roadHog);
	roadHog.SetOpponent(&mcCree);

	//Simulation loop
	while (running)
	{
		mcCree.Update(deltaTime);
		roadHog.Update(deltaTime);

		//Exit the loop if either character is out of HP
		if (mcCree.IsDead())
		{
			running = false;
			Summary(roadHog, mcCree);
		}
		else if (roadHog.IsDead())
		{
			running = false;
			Summary(mcCree, roadHog);
		}
	}

	return 0;
}
Character.h

Code: Select all

#include <string>
#include <iostream>
#include "Weapon.h"
#pragma once


class Character
{
public:
	Character(const std::string name_in, const int health_in, Weapon& rWeapon_in);
	Character(const std::string name_in, const int health_in, Weapon& rWeapon_in, const float hookCoolDown_in, const bool hasHookSkill_in);
	void SetOpponent(Character* pOpponent_in);
	void Update(const float deltaTime);
	int GetHealth() const;
	void IsCloseCombat();
	void TakeDamage(const int damage);
	std::string GetName() const;
	void CombatMessage(const int damage) const;
	bool IsDead() const;

private:
	const std::string name;
	int health;
	bool closeCombat = false;
	Weapon& rWeapon;
	const float hookCoolodown = 0.0f;
	float hookCooldownCounter = 0.0f;
	const bool hasHookSkill = false;
	Character* pOpponent = nullptr;
};
Character.cpp

Code: Select all

#include "Character.h"

Character::Character(const std::string name_in, const int health_in, Weapon & rWeapon_in)
	:
	name(name_in),
	health(health_in),
	rWeapon(rWeapon_in)
{}

Character::Character(const std::string name_in, const int health_in, Weapon & rWeapon_in, const float hookCoolDown_in, const bool hasHookSkill_in)
	:
	name(name_in),
	health(health_in),
	rWeapon(rWeapon_in),
	hookCoolodown(hookCoolDown_in),
	hasHookSkill(hasHookSkill_in)
{}

void Character::SetOpponent(Character * pOpponent_in)
{
	pOpponent = pOpponent_in;
}

void Character::Update(const float deltaTime)
{
	if (!closeCombat && hasHookSkill)
	{
		if (hookCooldownCounter >= hookCoolodown)
		{
			std::cout << name << " used his special hook skill to get into close combat.\n" << std::endl;
			closeCombat = true;
			pOpponent->IsCloseCombat();
		}

		hookCooldownCounter += deltaTime;
	}

	if (rWeapon.Shoot(deltaTime))
	{	
		if (closeCombat)
		{
			const int damageNear = rWeapon.GetDamageNear();
			pOpponent->TakeDamage(damageNear);
			CombatMessage(damageNear);
		}
		else
		{
			const int damageFar = rWeapon.GetDamageFar();
			pOpponent->TakeDamage(damageFar);
			CombatMessage(damageFar);
		}
	}
	
	rWeapon.Update(deltaTime, name);
}

int Character::GetHealth() const
{
	return health;
}

void Character::IsCloseCombat()
{
	closeCombat = true;
}

void Character::TakeDamage(const int damage)
{
	health -= damage;

	if (health < 0)
	{
		health = 0;
	}
}

std::string Character::GetName() const
{
	return name;
}

void Character::CombatMessage(const int damage) const
{
	const std::string opponentName = pOpponent->GetName();
	std::cout << name << " shot " << opponentName << " and dealt " << damage << " damage." << std::endl;
	std::cout << opponentName << " has " << pOpponent->GetHealth() << " HP left.\n" << std::endl;
}

bool Character::IsDead() const
{
	return health <= 0;
}
Weapon.h

Code: Select all

#include <iostream>
#include <string>
#pragma once

class Weapon
{
public:
	Weapon(const int damageFar_in, const int damageNear_in, const int magazineSize_in, const float reloadTime_in, const float fireRate_in);
	void Update(const float deltaTime, std::string name);
	bool Shoot(const float deltaTime);
	void Reload();
	int GetDamageNear() const;
	int GetDamageFar() const;
	bool HasBullets() const;

private:
	const int damageFar;
	const int damageNear;
	const int magazineSize;
	int bulletsLeft;
	const float reloadTime;
	const float fireRate;
	float reloadCounter = 0.0f;
	float bulletCooldownCounter;
	bool isReloaded = true;
};
Weapon.cpp

Code: Select all

#include "Weapon.h"

Weapon::Weapon(const int damageFar_in, const int damageNear_in, const int magazineSize_in, const float reloadTime_in, const float fireRate_in)
	:
	damageFar(damageFar_in),
	damageNear(damageNear_in),
	magazineSize(magazineSize_in),
	bulletsLeft(magazineSize_in),
	reloadTime(reloadTime_in),
	fireRate(fireRate_in),
	bulletCooldownCounter(fireRate_in)
{}

void Weapon::Update(const float deltaTime, std::string name)
{
	if (!HasBullets())
	{
		if ((reloadCounter += deltaTime) >= reloadTime)
		{
			Reload();
			std::cout << name << " reloaded.\n" << std::endl;
		}
	}
}

bool Weapon::Shoot(const float deltaTime)
{
	if ((bulletCooldownCounter += deltaTime) >= fireRate && HasBullets())
	{
		bulletCooldownCounter = 0.0f;
		--bulletsLeft;
		return true;
	}
	
	return false;
}

void Weapon::Reload()
{
	reloadCounter = 0.0f;
	bulletsLeft = magazineSize;
}

int Weapon::GetDamageNear() const
{
	return damageNear;
}

int Weapon::GetDamageFar() const
{
	return damageFar;
}

bool Weapon::HasBullets() const
{
	return bulletsLeft > 0;
}
Feedback is always appreciated!

Tuesday is dedicated to finishing the assignment and there's no lectures. Since I'm already done, I'll spend that time researching a bit about some of the stuff on the list of course content.

btw, our programing teacher is great. Really liked him, he had a chili type sense of humor

User avatar
chili
Site Admin
Posts: 3948
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: Noob learns to code in 3 months

Post by chili » September 5th, 2017, 1:35 am

Seems cool. The course plan has a lot of content for just 2 weeks, but you have a good grasp of a lot of this stuff so it should be manageable. My dawg though, you gotta watch Intermediate up to Tutorial 6 though, it will serve you insanely well.
Chili

User avatar
Yumtard
Posts: 575
Joined: January 19th, 2017, 10:28 pm
Location: Idiot from northern Europe

Re: Noob learns to code in 3 months

Post by Yumtard » September 5th, 2017, 7:58 am

^ yeah that's what I thought as well. I guess it's because nobody is completely new to programming, but they still have to cover basics since it's possible that people have missed some of it (like I have just very briefly looked at polymorphism) and some of us has only worked with c# so those will need to get familiar with the syntax and pointers etc

yeah I plan to watch all the intermediates this week :)
Today is pretty much off so will try and watch 1-6. Hopefully thursday will be similar unless the assignment on wednesday is much harder. So I'll watch the rest then and on the weekend. Also plan to read up on a few of the topics in my book

User avatar
Yumtard
Posts: 575
Joined: January 19th, 2017, 10:28 pm
Location: Idiot from northern Europe

Re: Noob learns to code in 3 months

Post by Yumtard » September 5th, 2017, 7:02 pm

Alrighty. Watched 1-3 today. Was very active during 3 so it took some time. Paused before chili made all the functions and made them myself. Was kinda surprised how well I did :D

Will probably watch 4-6 on thursday depending on how hard next assignment is and then watch the rest this weekend

User avatar
Yumtard
Posts: 575
Joined: January 19th, 2017, 10:28 pm
Location: Idiot from northern Europe

Re: Noob learns to code in 3 months

Post by Yumtard » September 6th, 2017, 10:27 am

Todays lecture went over references, pointers, structs and some const correctness.

2nd assignment is to refactor our program by creating new types and moving repeated code into functions. This I've already done in the first assignment so not much to do there.
I'll check to see if i can add some more since it says "several custom data structures" and I only have one for weapon and one for character.

we're also supposed to make some changes. one of the characters should carry 2 weapons and switch between those two. The second weapon is also different than the other ones.

Will start working on the assignment tonight

User avatar
chili
Site Admin
Posts: 3948
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: Noob learns to code in 3 months

Post by chili » September 6th, 2017, 2:54 pm

Dude, props for doing the coding before its demo'd in the video. 4 and 5 shouldn't be super hard for you, there will be a lot that you already know. But there will also be nuggets of new info, and the homework should be mildly amusing. T6 is where it is at though. The homework for T6 is also off the chain brah.

Homework for the course sounds good. It's only console stuff, but they manage to keep the matter interesting. Good luck broseph ;)
Chili

User avatar
Yumtard
Posts: 575
Joined: January 19th, 2017, 10:28 pm
Location: Idiot from northern Europe

Re: Noob learns to code in 3 months

Post by Yumtard » September 6th, 2017, 10:47 pm

^ Thanks chili :D Well I have watched that tutorial before so that kinda helped :P
Looking forward to the rest of the series! You're making me wanna skip straight to 6 :p

I def like the assignments so far. It feels like actually creating something even though it's something dumb. Also I like that it's possible to finish these in a multitude of ways.

I've rewritten the program. Not quite sure I like it :p
I'm new to inheritance (and we haven't gone through it in school yet) and am not sure if I'm doing it well.
Does it matter what the virtual functions in Character does (atm mine just do worthless bs) if they will only be needed for CharacterMcCree and CharacterRoadHog anyways?

Also, wasn't quite sure how to deal with this 2 weapons and switching between them thingy.
Ended up doing a second class for the new weapon (taunt pole) and using enums in CharacterRoadHog to decide which weapon to use in attack

I'm not sure how the extensibility is in this code..

Full task:
Refactor your program by creating new data types and moving repeated code into functions.
Roadhog now carries two wepons, his scrap gun which stays the same as in previous assignment but now also a taunt pole. The taunt pole is a stick with a horrible message to McCree written on it. It has no gameplay effect..
Roadhog switches between the two weapons every 2 seconds. If he switches mit reload the reload will have to start over once the weapon is switched back to. roadhog always begins with the scrapgun.
Refactor your program to support weapon switching and update the simulation to swap Roadhogs gun every two seconds

Here's how I did the weapon switching

Code: Select all

void CharacterRoadHog::Update(const float deltaTime)
{
	if (!IsDead())
	{
		switch (weapon)
		{
		case _ScrapGun:
			rScrapGun.Update(deltaTime, name);

			if (weaponSwitchTimer.limitReached())
			{
				rScrapGun.ResetReloadTimer();
				weapon = _TauntPole;
			}

			break;
		case _TauntPole:
			tauntPole.Update(deltaTime, name);

			if (weaponSwitchTimer.limitReached())
			{
				weapon = _ScrapGun;
			}
			break;
		}

		if (!closeCombat)
		{
			SpecialAttack();
		}
		
		specialAttackTimer.Update(deltaTime);
		weaponSwitchTimer.Update(deltaTime);
		Attack();
	}
}

void CharacterRoadHog::Attack()
{
	switch (weapon)
	{
	case _ScrapGun:
		if (rScrapGun.Shoot(pOpponent->GetName(), name))
		{
			if (closeCombat)
			{
				pOpponent->TakeDamage(rScrapGun.GetDamageNear());
			}
			else
			{
				pOpponent->TakeDamage(rScrapGun.GetDamageFar());
			}
		}
		break;

	case _TauntPole:
		tauntPole.Attack(name);
		break;
	}
}

Here's my inheritance

Character

Code: Select all

#pragma once

#include <string>
#include <iostream>

class Character
{
public:
	Character(const std::string name_in, const int health_in);
	void SetOpponent(Character* pOpponent_in); 
	virtual void Update(const float deltaTime); 
	virtual void Attack();
	virtual void SpecialAttack();
	int GetHealth() const;
	void IsCloseCombat();
	void TakeDamage(const int damage);
	const std::string& GetName() const;
	bool IsDead() const;

protected:
	const std::string name;
	int health;
	bool closeCombat = false; 
	Character* pOpponent = nullptr; 
};

Code: Select all

#include "Character.h"

Character::Character(const std::string name_in, const int health_in)
	:
	name(name_in),
	health(health_in)
{}

void Character::SetOpponent(Character * pOpponent_in)
{
	pOpponent = pOpponent_in;
}

void Character::Update(const float deltaTime)
{
	Attack();
}

void Character::Attack()
{
	std::cout << name << " attacked!\n";
}

void Character::SpecialAttack()
{
	std::cout << name << " used his special Attack!\n";
}

int Character::GetHealth() const
{
	return health;
}

void Character::IsCloseCombat()
{
	closeCombat = true;
}

void Character::TakeDamage(const int damage)
{
	health -= damage;

	if (health < 0)
	{
		health = 0;
	}
	std::cout << name << " took " <<  damage <<" damage\n"
		<< name << " has " << health << " HP left.\n\n";
}

const std::string& Character::GetName() const
{
	return name;
}

bool Character::IsDead() const
{
	return health <= 0;
}

CharacterMcCree

Code: Select all

#pragma once

#include "Character.h"
#include "Gun.h"

class CharacterMcCree :
	public Character
{
public:
	CharacterMcCree(const std::string name_in, const int health_in, Gun& rRevolver_in);
	virtual void Update(const float deltaTime);
	virtual void Attack();

private:
	Gun& rRevolver;
};

Code: Select all

#include "CharacterMcCree.h"

CharacterMcCree::CharacterMcCree(const std::string name_in, const int health_in, Gun& rRevolver_in)
	:
	Character(name_in, health_in),
	rRevolver(rRevolver_in)
{}

void CharacterMcCree::Update(const float deltaTime)
{
	if (!IsDead())
	{
		rRevolver.Update(deltaTime, name);
		Attack();
	}
}

void CharacterMcCree::Attack()
{
	if (rRevolver.Shoot(pOpponent->GetName(), name))
	{
		if (closeCombat)
		{
			pOpponent->TakeDamage(rRevolver.GetDamageNear());
		}
		else
		{
			pOpponent->TakeDamage(rRevolver.GetDamageFar());
		}
	}
}

CharacterRoadHog

Code: Select all

#pragma once

#include "Character.h"
#include "Timer.h"
#include "Gun.h"
#include "TauntPole.h"
#include <string>

class CharacterRoadHog :
	public Character
{
public:
	CharacterRoadHog(const std::string name_in, const int health_in, Gun& rScrapGun_in, TauntPole& rTauntPole_in, 
		float specialAttackTimeLimit, float weaponSwitchTimeLimit);
	enum WeaponType
	{
		_ScrapGun, _TauntPole
	};
	virtual void Update(const float deltaTime);
	virtual void SpecialAttack();
	virtual void Attack();

private:
	Timer specialAttackTimer;
	Timer weaponSwitchTimer;
	Gun& rScrapGun;
	TauntPole& tauntPole;
	WeaponType weapon = _ScrapGun;
};

Code: Select all

#include "CharacterRoadHog.h"

CharacterRoadHog::CharacterRoadHog(const std::string name_in, const int health_in, Gun & rScrapGun_in, TauntPole& rTauntPole_in, 
	float specialAttackTimeLimit, float weaponSwitchTimeLimit)
	:
	Character(name_in, health_in),
	specialAttackTimer(specialAttackTimeLimit),
	rScrapGun(rScrapGun_in),
	tauntPole(rTauntPole_in),
	weaponSwitchTimer(weaponSwitchTimeLimit)
{}

void CharacterRoadHog::Update(const float deltaTime)
{
	if (!IsDead())
	{
		switch (weapon)
		{
		case _ScrapGun:
			rScrapGun.Update(deltaTime, name);

			if (weaponSwitchTimer.limitReached())
			{
				rScrapGun.ResetReloadTimer();
				weapon = _TauntPole;
			}

			break;
		case _TauntPole:
			tauntPole.Update(deltaTime, name);

			if (weaponSwitchTimer.limitReached())
			{
				weapon = _ScrapGun;
			}
			break;
		}

		if (!closeCombat)
		{
			SpecialAttack();
		}
		
		specialAttackTimer.Update(deltaTime);
		weaponSwitchTimer.Update(deltaTime);
		Attack();
	}
}

void CharacterRoadHog::SpecialAttack()
{
	if (specialAttackTimer.limitReached())
	{
		std::cout << name << " used his special hook skill to get into close combat.\n" << std::endl;
		closeCombat = true;
		pOpponent->IsCloseCombat();
	}
}

void CharacterRoadHog::Attack()
{
	switch (weapon)
	{
	case _ScrapGun:
		if (rScrapGun.Shoot(pOpponent->GetName(), name))
		{
			if (closeCombat)
			{
				pOpponent->TakeDamage(rScrapGun.GetDamageNear());
			}
			else
			{
				pOpponent->TakeDamage(rScrapGun.GetDamageFar());
			}
		}
		break;

	case _TauntPole:
		tauntPole.Attack(name);
		break;
	}
}


Thoughts?

User avatar
Yumtard
Posts: 575
Joined: January 19th, 2017, 10:28 pm
Location: Idiot from northern Europe

Re: Noob learns to code in 3 months

Post by Yumtard » September 6th, 2017, 11:30 pm

Made a small change in CharacterRoadHog and added SwitchWeapon(). Maybe this should be a virtual function in Character even though CharacterMcCree currently only have one weapon :S I'm not sure.

Anyways, here's the full code if anyones interested. Should probably post code like this instead of clogging up the page with a bunch of code

https://github.com/Yumtard/CombatSimulator

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Noob learns to code in 3 months

Post by albinopapa » September 7th, 2017, 3:27 am

Just out of curiosity,

Code: Select all

	CharacterMcCree(const std::string& name_in, const int health_in, Gun& rRevolver_in);
	virtual void Update(const float deltaTime);
	virtual void Attack();
Has the instructor covered 'override'?

Code: Select all

	CharacterMcCree(const std::string& name_in, const int health_in, Gun& rRevolver_in);
	virtual void Update(const float deltaTime) override;
	virtual void Attack() override;
While not necessary if the base class's virtual functions aren't = 0, I thought it was good practice to use override, mostly to make sure that the child classes virtual functions are called when a base pointer is used.

Let's say you had done this instead:

Code: Select all

int main()
{
	//Variables
	const std::string roadHogName = "RoadHog";
	const std::string mcCreeName = "McCree";
	Gun revolver(35, 70, 6, 1.5f, 0.5f);
	Gun scrapGun(20, 255, 4, 1.5f, 1.0f);
	TauntPole tauntPole(1.0f);
	
	constexpr size_t numCharacters = 2;
	Character *pCharacters[numCharacters];
	pCharacters[0] = new CharacterMcCree(mcCreeName, 200, revolver);
	pCharacters[1] = new CharacterRoadHog(roadHogName, 600, scrapGun, tauntPole, 30.f, 2.f);
	const float deltaTime = 0.1f;
	bool running = true;

	pCharacters[0]->SetOpponent(pCharacters[1]);
	pCharacters[1]->SetOpponent(pCharacters[0]);

	//Simulation loop
	while (running)
	{
		for(size_t i = 0; i < numCharacters; ++i)
		{
			// Since pCharacters[i] is a Character pointer, the compiler
			// will call Character::Update.  One because it has a default 
			// definition, and two because you didn't specify that it has an 
			// override.
			pCharacters[i]->Update(deltaTime);
		}

		//Exit the loop if either character is out of HP
		if (pCharacters[0]->IsDead())
		{
			if (pCharacters[1]->IsDead())
			{
				Draw();
			}
			else
			{
				Summary(*pCharacters[1], *pCharacters[0]);
			}
			
			running = false;
		}
		else if (pCharacters[1]->IsDead())
		{
			Summary(*pCharacters[0], *pCharacters[1]);
			running = false;
		}
	}
	// And good to clean up memory
	for(size_t i = 0; i < numCharacters; ++i)
	{
		delete pCharacters[i];
		pCharacters[i] = nullptr;
	}
	return 0;
}
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
Yumtard
Posts: 575
Joined: January 19th, 2017, 10:28 pm
Location: Idiot from northern Europe

Re: Noob learns to code in 3 months

Post by Yumtard » September 7th, 2017, 2:21 pm

Thanks papa! No we haven't gone through this stuff at all, I'm just messing around on my own with it.

So I assume it's kosher to have a Character * that stores CharacterMcCree? at least I assumed so reading your code.

With that assumption I decided to try and improve the extensibility of my code a bit by making it easier to add more weapons...... man that had me confused for hours. Not sure how my code even looks now, will check if it needs any cleaning up.

anyways, in main now I also make pointers to the weapons I create, then I have an AddWeapon function that works like this

Code: Select all

void Character::AddWeapon(Weapon * weapon_in)
{
	numWeapons++;
	weapons.push_back(weapon_in);
}
and I changed the system for switching weapons to this:

Code: Select all

void Character::SwitchWeapon()
{
	weapons[curWeapon]->Reset();

	if ((curWeapon + 1) == numWeapons)
	{
		curWeapon = 0;
	}
	else
	{
		curWeapon++;
	}
}
So then in update etc I just go:
weapons[curWeapon]->Update(deltaTime);

instead of switch statements checking for enums...

I feel like it's now easier to add new stuff. like to give roadHog a new weapon you'd just do this in main:

Gun lol(x, y, z, blah, blah, blah);
Weapon* pLol = &lol;
roadHog.AddWeapon(pLol);

and it's done.

Again not sure if this is "legal" or if my code is as much of a confusing mess as it feels like atm :D

https://github.com/Yumtard/CombatSimula ... e/dynomite

Post Reply