diff options
| author | Paweł Redman <pawel.redman@gmail.com> | 2017-12-12 14:57:52 +0100 | 
|---|---|---|
| committer | Paweł Redman <pawel.redman@gmail.com> | 2017-12-12 14:57:52 +0100 | 
| commit | 1fd33b69f7cef5f9dfe1da417717545f34c673d0 (patch) | |
| tree | dd30ac53136a54b159018bf4aea6d09d77d376fb /src/game | |
| parent | 9f88509c8e440d9bb3430b71708efd69988f461c (diff) | |
Start moving game logic to src/game.
Diffstat (limited to 'src/game')
| -rw-r--r-- | src/game/assets.cpp | 20 | ||||
| -rw-r--r-- | src/game/game.cpp | 270 | ||||
| -rw-r--r-- | src/game/game.hpp | 14 | ||||
| -rw-r--r-- | src/game/interface.cpp | 134 | 
4 files changed, 438 insertions, 0 deletions
diff --git a/src/game/assets.cpp b/src/game/assets.cpp new file mode 100644 index 0000000..32eff81 --- /dev/null +++ b/src/game/assets.cpp @@ -0,0 +1,20 @@ +#include "game.hpp" + +namespace assets { + +human_assets_t human; +sf::Texture tile_dirt; +sf::Texture tile_wall; + +void load(void) +{ +	human.head_idle.load("assets/units/human/head_idle", 1, 1, 1); +	human.body_idle.load("assets/units/human/body_idle", 2, 2, 2); +	human.legs_idle.load("assets/units/human/legs_idle", 2, 2); +	human.legs_walking.load("assets/units/human/legs_walking", 2, 2); + +	tile_dirt.loadFromFile("assets/tiles/dirt.png"); +	tile_wall.loadFromFile("assets/tiles/wall.png"); +} + +} // namespace assets diff --git a/src/game/game.cpp b/src/game/game.cpp new file mode 100644 index 0000000..eb3966d --- /dev/null +++ b/src/game/game.cpp @@ -0,0 +1,270 @@ +#include "game.hpp" + +namespace game { + +static size_t selection_cookie = 1; + +enum { +	ET_UNIT +}; + +class unit_t : public world::entity_t { +protected: +	world::world_t *world; + +	world::cmodel_t make_cmodel(v2f_t at) +	{ +		world::cmodel_t cmodel; + +		cmodel.bounds[0] = at + size[0]; +		cmodel.bounds[1] = at + size[1]; +		cmodel.cflags = cflags; + +		return cmodel; +	} + +	void compute_bounds() +	{ +		render_bounds[0] = x + render_size[0]; +		render_bounds[1] = x + render_size[1]; +	} + +public: +	v2f_t x; +	rectf_t size, render_size; +	world::cflags_t cflags; +	size_t selected = 0; + +	unit_t() : entity_t(ET_UNIT) +	{ +	} + +	struct { +		bool moving = false; +		v2f_t dst; +		float angle = 0.0f; + +		std::list<v2f_t> path; + +		bool blocked; +		size_t attempts_left; +		float next_attempt; +	} move; + +	const wchar_t *say_text; +	double say_time = -INFINITY; + +	void say(const wchar_t *wstr, double now) +	{ +		say_text = wstr; +		say_time = now; +		std::cout << (void*)this << ": " << wstr << "\n"; +	} + +	void place(world::world_t *world_, v2f_t x_) +	{ +		world = world_; +		x = x_; +		move.moving = false; +		cflags = 1; + +		unlink(); +		cmodel = make_cmodel(x); +		compute_bounds(); +		link(world); +	} + +	void keep_moving(double now, double dt) +	{ +		float time; + +		if (!move.moving) +			return; + +		if (move.blocked && now < move.next_attempt) +			return; + +		time = dt * 10; + +		while (time > 0.0f) { +			v2f_t delta, next, x_new; +			world::cmodel_t cmodel_next; + +			if (!move.path.size()) { +				move.moving = false; +				break; +			} + +			next = *move.path.begin(); +			delta = next - x; +			move.angle = delta.angle(); + +			if (delta.len() >= time) { +				x_new = x + delta * time / delta.len(); +				time -= delta.len(); +			} else { +				x_new = next; +				time -= delta.len(); +				move.path.pop_front(); +			} + +			cmodel_next = make_cmodel(x_new); +			if (!world->test_rect(&cmodel_next, this)) { +				x = x_new; +				cmodel = cmodel_next; +				continue; +			} + +			if (move.attempts_left) { +				move.blocked = true; +				move.attempts_left--; +				move.next_attempt = now + 0.2f; +			} else { +				if ((x - move.dst).len() > 1.5f) +					say(text::unit_blocked, now); +				move.moving = false; +			} +			break; +		} + + +		unlink(); +		compute_bounds(); +		link(world); +	} + +	bool start_moving(v2f_t dst_, double now) +	{ +		if (!world) { +			printf("unit_t::start_moving: entity is not linked\n"); +			return false; +		} + +		move.dst = dst_; +		move.path.clear(); + +		if (!world->find_path(x, move.dst, &cmodel, this, &move.path)) { +			say(text::unit_no_path, now); +			move.moving = false; +			return false; +		} + +		move.moving = true; + +		move.blocked = false; +		move.attempts_left = 10; +		move.next_attempt = -INFINITY; + +		return true; +	} +}; + +class human_t : public unit_t { +public: +	human_t() +	{ +		size[0] = v2f_t(-0.4f, -0.4f); +		size[1] = v2f_t(+0.4f, +0.4f); +		render_size[0] = v2f_t(-0.5f, -1.0f); +		render_size[1] = v2f_t(+0.5f, +0.5f); +	} + +	void render_to(render::state_t *render) +	{ +		bool moving; + +		if (selected == selection_cookie) +			render->render_hlrect(render_bounds, sf::Color::Blue); + +		moving = move.moving && !move.blocked; + +		render->render((moving ? &assets::human.legs_walking : +		               &assets::human.legs_idle), render_bounds, move.angle); +		render->render(&assets::human.body_idle, render_bounds, move.angle); +		render->render(&assets::human.head_idle, render_bounds, move.angle); + +		{ +			v2f_t x1; +			static float t = 0; +			world::trace_t trace; + +			t += 0.02f; + +			x1[0] = x[0] + cos(t) * 5; +			x1[1] = x[1] + sin(t) * 5; +			trace = world->trace(x, x1, 1); +			render->render_arrow(x, trace.end, sf::Color::Green); +		} + +		if (move.moving && debug_draw_paths) +			render->debug_path(&move.path); + +		if (say_time + 5.0 > render->now) { +			v2f_t text_pos; +			float height; + +			text_pos = render_bounds[0] + v2f_t(render_bounds.dim(0) / 2, -render_bounds.dim(1) * 0.1); +			height = size.dim_min() * 0.20f; +			render->render_text(text_pos, height, say_text, +			                    render::ALIGN_CENTER_BOTTOM, +			                    sf::Color::White); +		} +	} +}; + +void state_t::start(void) +{ +	human_t *human; + +	human = new human_t; +	human->place(&world, v2f_t(0.5, 0.5)); +	units.insert(human); +} + +void state_t::stop(void) +{ +	// FIXME +	/* +	for (unit_t *unit : units) +		delete unit; +	*/ +} + +void state_t::select(rectf_t x) +{ +	selection_cookie++; +	selected_units.clear(); + +	for (world::entity_t *ent : world.get_render_entities(x)) { +		unit_t *unit; + +		if (ent->type != ET_UNIT) +			continue; + +		unit = (unit_t*)ent; +		unit->selected = selection_cookie; +		selected_units.insert(unit); +	} +} + +void state_t::command(v2f_t x) +{ +	v2f_t snap; + +	snap[0] = std::round(x[0] - 0.5f) + 0.5f; +	snap[1] = std::round(x[1] - 0.5f) + 0.5f; + +	for (unit_t *unit : selected_units) +		unit->start_moving(snap, now); +} + +void state_t::tick(double now_, double dt_) +{ +	now = now_; +	dt = dt_; + +	for (unit_t *unit : units) +		unit->keep_moving(now, dt); +} + +} //namespace game diff --git a/src/game/game.hpp b/src/game/game.hpp new file mode 100644 index 0000000..3e10bbb --- /dev/null +++ b/src/game/game.hpp @@ -0,0 +1,14 @@ +#include "../common.hpp" + +namespace assets { +	typedef struct { +		render::oriented_sprite_4M_t head_idle, body_idle; +		render::oriented_sprite_4M2_t legs_idle, legs_walking; +	} human_assets_t; + +	extern human_assets_t human; +	extern sf::Texture tile_dirt; +	extern sf::Texture tile_wall; + +	void load(void); +}; diff --git a/src/game/interface.cpp b/src/game/interface.cpp new file mode 100644 index 0000000..c89cdad --- /dev/null +++ b/src/game/interface.cpp @@ -0,0 +1,134 @@ +#include "game.hpp" + +namespace interface { + +state_t::state_t(sf::RenderWindow *window_, game::state_t *game_) +{ +	window = window_; +	game = game_; +} + +static sf::Vector2f compute_pan(sf::RenderWindow *window, sf::Vector2f pan_ref) +{ +	sf::Vector2i mouse = sf::Mouse::getPosition(*window); +	sf::Vector2f vmouse = window->mapPixelToCoords(mouse); +	return -(vmouse - pan_ref); +} + +void state_t::tick(double dt) +{ +	sf::Vector2u size; +	sf::Event event; +	sf::Vector2f view_size; +	v2f_t wmouse; // Mouse position in world space; + +	size = window->getSize(); + +	camera.zoom = expfade(camera.zoom, camera.target_zoom, 15, dt); + +	{ +		float view_scale; + +		view_scale = 3 * exp(camera.zoom * 0.3); +		if (size.x > size.y) { +			view_size.y = view_scale; +			view_size.x = view_scale * size.x / size.y; +		} else { +			view_size.x = view_scale; +			view_size.y = view_scale * size.y / size.x; +		} + +		window->setView(sf::View(camera.center, view_size)); +	} + + +	while (window->pollEvent(event)) { +		// FIXME: refactor this nested switch clusterfuck +		switch (event.type)  { +		case sf::Event::Closed: +			window->close(); +			return; + +		case sf::Event::MouseButtonPressed: +			wmouse = window->mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y)); +  +			switch (event.mouseButton.button) { +			case sf::Mouse::Button::Left: +				select.selecting = true; +				select.rect[0] = wmouse; +				select.rect[1] = wmouse; +				break; + +			case sf::Mouse::Button::Right: +				game->command(wmouse); +				break; + +			case sf::Mouse::Button::Middle: +				camera.panning = true; +				camera.pan_ref = wmouse; +				break; + +			default:; +			} +			break; + +		case sf::Event::MouseButtonReleased: +			switch (event.mouseButton.button) { +			case sf::Mouse::Button::Left: +				if (select.selecting) +					game->select(select.rect); +				select.selecting = false; +				break; + +			case sf::Mouse::Button::Middle: +				if (camera.panning) +					camera.center += compute_pan(window, camera.pan_ref); +				camera.panning = false; +				break; + +			default:; +			} +			break; + +		case sf::Event::MouseWheelScrolled: +			camera.target_zoom -= event.mouseWheelScroll.delta; +			if (camera.target_zoom < 0) +				camera.target_zoom = 0; +			if (camera.target_zoom > 11) +				camera.target_zoom = 11; +			break; + +		case sf::Event::KeyPressed: +			switch (event.key.code) { +			case sf::Keyboard::Key::F1: +				debug_draw_cmodels ^= 1; +				break; + +			case sf::Keyboard::Key::F2: +				debug_draw_paths ^= 1; +				break; + +			case sf::Keyboard::Key::F3: +				debug_draw_tile_coords ^= 1; +				break; + +			default:; +			} +		default:; +		} +	} + +	if (camera.panning) { +		sf::Vector2f delta = compute_pan(window, camera.pan_ref); +		window->setView(sf::View(camera.center + delta, view_size)); +	} else +		window->setView(sf::View(camera.center, view_size)); + +	// Compute this _after_ the setView above. +	wmouse = window->mapPixelToCoords(sf::Mouse::getPosition(*window)); + +	if (select.selecting) +		select.rect[1] = wmouse; +} + +} // namespace interface  | 
