티스토리 뷰

* 인프런에 있는 "홍정모의 게임 만들기 연습 문제 패키지" 강의를 바탕으로 작성된 글입니다.

 

1. moveUp외에 다른 방향 이동과 총 쏘기 등도 구현해보기.

#pragma once

#include "Game2D.h"
#include "SoundEngine_Singleton.h"
#include <list>
#include <map>
#include <stdio.h>
#include <fstream>
#include "Command.h"

namespace shyplants
{
	class MyBullet
	{
	public:
		vec2 center = vec2(0.0f, 0.0f);
		vec2 velocity = vec2(0.0f, 0.0f);

		void draw()
		{
			beginTransformation();
			translate(center);
			drawFilledRegularConvexPolygon(Colors::yellow, 0.02f, 8);
			drawWiredRegularConvexPolygon(Colors::gray, 0.02f, 8);
			endTransformation();
		}

		void update(const float& dt)
		{
			center += velocity * dt;
		}
	};

	class MyTank : public Actor, public MyBullet
	{
	public:
		vec2 center = vec2(0.0f, 0.0f);
		MyBullet *bullet = nullptr;
		std::list<MyBullet*> bulletList;

		~MyTank()
		{
			for (auto iter = bulletList.begin(); iter != bulletList.end();)
			{
				delete *iter;
				iter = bulletList.erase(iter);
			}
		}

		void shoot(float dt) override
		{
			bulletList.push_back(new MyBullet);
			bulletList.back()->center = center;
			bulletList.back()->center.x += 0.2f;
			bulletList.back()->center.y += 0.1f;
			bulletList.back()->velocity = vec2(2.0f, 0.0f);
		}

		void moveUp(float dt) override
		{
			center.y += 0.5f * dt;
		}

		void moveDown(float dt) override
		{
			center.y += -0.5f * dt;
		}

		void moveLeft(float dt) override
		{
			center.x += -0.5f * dt;
		}

		void moveRight(float dt) override
		{
			center.x += 0.5f * dt;
		}

		void update(const float& dt)
		{
			// 총알 리스트를 순회하며 업데이트, 드로우 함수 호출
			for (auto iter = bulletList.begin(); iter != bulletList.end(); iter++)
			{
				(*iter)->update(dt);
				(*iter)->draw();
			}

			// 총알 리스트를 순회하며 화면 밖에 나간 총알 메모리 해제 (메모리 누수 방지)
			for (auto iter = bulletList.begin(); iter != bulletList.end();)
			{
				/*
					list 컨테이너의 erase함수는 삭제된 다음 원소를 반환한다.
					따라서 Iterator 중복증가를 방지하기 위해 분리시킨다.
				*/
				if ((*iter)->center.x > 2.0f) {
					delete *iter;
					iter = bulletList.erase(iter);
				}
				else {
					iter++;
				}
			}
		}

		void draw()
		{
			beginTransformation();
			{
				translate(center);
				drawFilledBox(Colors::green, 0.25f, 0.1f); // body
				translate(-0.02f, 0.1f);
				drawFilledBox(Colors::blue, 0.15f, 0.09f); // turret
				translate(0.15f, 0.0f);
				drawFilledBox(Colors::red, 0.15f, 0.03f);  // barrel
			}
			endTransformation();
		}
	};

	int keyString2Integer(char* key)
	{
		if (!strcmp(key, "SPACE")) return GLFW_KEY_SPACE;
		else if (!strcmp(key, "W")) return GLFW_KEY_W;
		else if (!strcmp(key, "S")) return GLFW_KEY_S;
		else if (!strcmp(key, "A")) return GLFW_KEY_A;
		else if (!strcmp(key, "D")) return GLFW_KEY_D;

		return -1;
	}

	class InputHandler
	{
	public:

		std::map<int, Command *> key_command_map;
		InputHandler()
		{}

		void readScript(const std::string filename)
		{
			FILE *script_file = nullptr;
			script_file = fopen(filename.c_str(), "r");

			int num_bindings = 5;
			for (int i = 0; i < num_bindings; ++i) {
				char key_script[255];
				char cmd_buffer[255];

				fscanf(script_file, "%s %s", key_script, cmd_buffer);

				key_command_map[keyString2Integer(key_script)] = CommandFactory::CreateCommand(std::string(cmd_buffer));
			}

			fclose(script_file);
		}

		int handleInput(Game2D& game, Actor& actor, float dt)
		{	
			for(auto& m : key_command_map)
			{
				if (m.first == GLFW_KEY_SPACE) {
					if (game.isKeyPressedAndReleased(m.first)) {
						m.second->execute(actor, dt);

						return 0;
					}
				}
				
				else if (game.isKeyPressed(m.first)) {
					m.second->execute(actor, dt);

					return 1;
				}
			}

			return -1;
		}
	};

	class TankExample : public Game2D
	{
	public:
		MyTank tank;
		InputHandler input_handler;

	public:
		TankExample()
			: Game2D("This is my digital canvas!", 1024, 768, false, 2)
		{
			auto& sound_engine = *SoundEngine_Singleton::getInstance();

			sound_engine.createSound("background.wav", "background_music", true);
			sound_engine.createSound("move.wav", "tank_move", true);
			sound_engine.createSound("shoot.ogg", "cannon", false);

			sound_engine.playSound("background_music");

			// key mapping
			input_handler.readScript("key_binding.txt");
		}

		~TankExample()
		{}

		void update() override
		{
			
			int input_ret = input_handler.handleInput(*this, tank, getTimeStep());

			auto& sound_engine = *SoundEngine_Singleton::getInstance();

			if (input_ret == -1)
				sound_engine.stopSound("tank_move");
			else if (input_ret == 0) {
				sound_engine.stopSound("cannon");
				sound_engine.playSound("cannon");
			}
			else if (input_ret == 1)
				sound_engine.playSound("tank_move");

			tank.update(getTimeStep());
			tank.draw();
		}
	};
}

 

 

댓글