Skip to content

Commit 2c7b8d7

Browse files
authored
Merge pull request #12 from mortennobel/develop
Update UI example
2 parents 6081960 + d88d0d8 commit 2c7b8d7

File tree

11 files changed

+208
-26
lines changed

11 files changed

+208
-26
lines changed

project/gui/CameraComponent.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//
2+
// Created by Morten Nobel Jørgensen on 2018-11-04.
3+
//
4+
5+
#include <SDL_events.h>
6+
#include "CameraComponent.hpp"
7+
#include "GameObject.hpp"
8+
#include "sre/Renderer.hpp"
9+
10+
CameraComponent::CameraComponent(GameObject *gameObject) : Component(gameObject) {
11+
12+
}
13+
14+
void CameraComponent::update(float deltaTime) {
15+
using namespace glm;
16+
17+
// find min and max dist in world space
18+
auto inst = sre::Renderer::instance;
19+
auto minWorldPos = clipToWorldspaceCoordinates({-safeArea, -safeArea, 0});
20+
auto centerWorldPos = clipToWorldspaceCoordinates({0, 0, 0});
21+
auto maxWorldPos = clipToWorldspaceCoordinates({+safeArea, +safeArea, 0});
22+
23+
vec3 pos ( target->getPosition(),0);
24+
vec3 newPos = glm::min(maxWorldPos, glm::max(minWorldPos, pos));
25+
if (pos != newPos){
26+
auto diff = newPos-pos;
27+
centerWorldPos -= diff;
28+
this->camera->lookAt(centerWorldPos, centerWorldPos + vec3(0,0,-1), vec3(0,1,0));
29+
}
30+
}
31+
32+
void CameraComponent::onGui() {
33+
34+
}
35+
36+
void CameraComponent::setTarget(std::shared_ptr<GameObject>& target) {
37+
this->target = target;
38+
}
39+
40+
void CameraComponent::setSize(float size) {
41+
this->size = size;
42+
camera->setOrthographicProjection(size, -1, 1);
43+
}
44+
45+
void CameraComponent::setCamera(sre::Camera *camera) {
46+
this->camera = camera;
47+
}
48+
49+
glm::vec2 CameraComponent::getWindowCoordinates(glm::vec3 worldpos){
50+
using namespace glm;
51+
vec4 w(worldpos, 1.0f);
52+
auto inst = sre::Renderer::instance;
53+
auto viewport = static_cast<glm::vec2>(inst->getDrawableSize());
54+
vec4 clipSpace = camera->getProjectionTransform(viewport) * camera->getViewTransform()*w;
55+
vec4 ndc = clipSpace/clipSpace.w;
56+
ndc.y *= -1;
57+
vec4 winCoords = ndc * 0.5f + 0.5f;
58+
return vec2(winCoords) * vec2(inst->getWindowSize());
59+
}
60+
61+
bool CameraComponent::onKey(SDL_Event &event) {
62+
if (event.type==SDL_KEYDOWN){
63+
switch(event.key.keysym.sym){
64+
case SDLK_1:
65+
setSize(size+1);
66+
break;
67+
case SDLK_2:
68+
setSize(size-1);
69+
break;
70+
}
71+
}
72+
}
73+
74+
glm::vec3 CameraComponent::clipToWorldspaceCoordinates(glm::vec3 clipCoordinates) {
75+
using namespace glm;
76+
auto inst = sre::Renderer::instance;
77+
auto viewport = static_cast<glm::vec2>(inst->getDrawableSize());
78+
glm::vec4 worldSpace = glm::inverse(camera->getViewTransform())*glm::inverse(camera->getProjectionTransform(viewport)) * vec4(clipCoordinates, 1.0);
79+
return glm::vec3(worldSpace);
80+
}

project/gui/CameraComponent.hpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// Created by Morten Nobel Jørgensen on 2018-11-04.
3+
//
4+
#pragma once
5+
6+
#include "Component.hpp"
7+
#include "sre/Camera.hpp"
8+
9+
// Create a game camera
10+
class CameraComponent : public Component{
11+
public:
12+
explicit CameraComponent(GameObject *gameObject);
13+
14+
void update(float deltaTime) override;
15+
16+
void onGui() override;
17+
18+
void setCamera(sre::Camera* camera);
19+
20+
void setSize(float size);
21+
22+
bool onKey(SDL_Event &event) override;
23+
24+
void setTarget(std::shared_ptr<GameObject>& target);
25+
26+
glm::vec2 getWindowCoordinates(glm::vec3 worldpos);
27+
glm::vec3 clipToWorldspaceCoordinates(glm::vec3 clipCoordinates);
28+
private:
29+
sre::Camera* camera;
30+
float size = 400;
31+
std::shared_ptr<GameObject> target;
32+
float safeArea = 0.3f; // percentage from center
33+
};
34+

project/gui/Hero.cpp

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ using namespace sre;
1414

1515
std::map<std::string, std::shared_ptr<sre::Texture>> Hero::inventoryTexture;
1616

17+
const int heartEmpty = 0;
18+
const int heartHalf = 1;
19+
const int heartFull = 2;
20+
1721
Hero::Hero(GameObject *gameObject)
1822
: Component(gameObject), velocity(0) {
1923
auto heroTexture = sre::Texture::create()
@@ -30,14 +34,20 @@ Hero::Hero(GameObject *gameObject)
3034
"Necklace",
3135
"Shield"};
3236

37+
heartIcons[heartEmpty] = Texture::create().withFile("assets/hud_heartEmpty.png").withFilterSampling(false).build();
38+
heartIcons[heartHalf] = Texture::create().withFile("assets/hud_heartHalf.png").withFilterSampling(false).build();
39+
heartIcons[heartFull] = Texture::create().withFile("assets/hud_heartFull.png").withFilterSampling(false).build();
40+
heartSize = {heartIcons[heartFull]->getWidth()*0.5f, heartIcons[heartFull]->getHeight()*0.5f};
41+
powerbar = Texture::create().withFile("assets/powerbar.png").withFilterSampling(false).build();
42+
powerbarSize = {heartSize.x*3,heartSize.y};
43+
3344
heroSpriteAtlas = SpriteAtlas::createSingleSprite(heroTexture, "hero");
3445

3546
auto spriteComponent = gameObject->addComponent<SpriteComponent>();
3647
auto sprite = heroSpriteAtlas->get("hero");
3748
heroSize = sprite.getSpriteSize();
3849
spriteComponent->setSprite(sprite);
3950

40-
gameObject->setPosition({305,200});
4151

4252
// setup font
4353
auto fonts = ImGui::GetIO().Fonts;
@@ -94,9 +104,10 @@ void Hero::guiSpeechBubble(){
94104
bool* open = nullptr;
95105

96106
auto heroPos = gameObject->getPosition();
107+
auto heroPosWin = cam->getWindowCoordinates(glm::vec3(heroPos, 0.0));
97108
ImVec2 popupSize(300, 50);
98109

99-
ImVec2 pos (heroPos.x - popupSize.x / 2, (winsize.y - heroPos.y) - popupSize.y - heroSize.y );
110+
ImVec2 pos (heroPosWin.x - popupSize.x / 2, heroPosWin.y - popupSize.y - heroSize.y );
100111
auto cond = ImGuiCond_Always;
101112
ImGui::SetNextWindowPos(pos, cond);
102113
ImGui::SetNextWindowSize(popupSize, cond);
@@ -111,7 +122,7 @@ void Hero::guiSpeechBubble(){
111122
void Hero::guiGameInfo() {
112123
auto r = Renderer::instance;
113124
auto winsize = r->getWindowSize();
114-
ImVec2 size = {220,60};
125+
ImVec2 size = {180, 107};
115126
ImVec2 pos = {winsize.x - size.x,0};
116127
auto cond = ImGuiCond_Always;
117128
ImVec2 pivot = {0,0};
@@ -127,32 +138,60 @@ void Hero::guiGameInfo() {
127138
ImGui::Begin("#gameinfo", open, flags);
128139
ImGui::PushFont(ProggyTiny);
129140

130-
// draw score
131-
ImGui::Text("Score"); ImGui::SameLine();
141+
// draw health
142+
ImGui::Text("Health");
143+
float width = heartSize.x*3;
144+
float windowWidth = 
ImGui::GetWindowContentRegionWidth();
145+
ImVec2 uv0(0,1); // flip y axis coordinates
146+
ImVec2 uv1(1,0);
147+
for (int i=0;i<3;i++){
148+
149+
ImGui::SameLine(windowWidth - width + heartSize.x * i);
150+
int texIndex = heartFull;
151+
if (i*2+1 == health){
152+
texIndex = heartHalf;
153+
} else if (i*2 > health){
154+
texIndex = heartEmpty;
155+
}
156+
Texture* tex = heartIcons[texIndex].get();
157+
ImGui::Image(tex->getNativeTexturePtr(),{heartSize.x,heartSize.y}, uv0, uv1);
158+
}
159+
160+
// draw Score
161+
ImGui::PushID(1);
132162
auto scoreStr = std::to_string(score);
133-
float windowWidth = 
 ImGui::GetWindowContentRegionWidth();
134-
float width = ImGui::CalcTextSize(scoreStr.c_str()).x;
163+
ImGui::Text("Score"); ImGui::SameLine();
164+
width = ImGui::CalcTextSize(scoreStr.c_str()).x;
135165
ImGui::SetCursorPosX(windowWidth - width); // align right
136166
ImGui::Text(scoreStr.c_str());
167+
ImGui::PopID();
137168

138-
// draw health
139-
ImGui::PushID(1);
140-
auto healthStr = std::to_string(health);
141-
ImGui::Text("Health"); ImGui::SameLine();
142-
width = ImGui::CalcTextSize(healthStr.c_str()).x;
169+
// Draw powerbar
170+
ImGui::Text("Power"); ImGui::SameLine();
171+
width = powerbarSize.x;
143172
ImGui::SetCursorPosX(windowWidth - width); // align right
144-
ImGui::Text(healthStr.c_str());
145-
ImGui::PopID();
173+
// Draw background
174+
ImGui::Image(powerbar->getNativeTexturePtr(),{powerbarSize.x,powerbarSize.y}, uv0, uv1); ImGui::SameLine();
175+
float border=3;
176+
auto innerSize = powerbarSize - glm::vec2(border*2,border*2);
177+
ImGui::SetCursorPosX(windowWidth - width + border); // align right
178+
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + border); // move down
179+
// scale/clip inner bar
180+
innerSize.x *= power;
181+
uv1.x *= power;
182+
ImVec4 tintColor(0,1,0,1);
183+
ImGui::Image(powerbar->getNativeTexturePtr(),{innerSize.x,innerSize.y}, uv0, uv1, tintColor);
146184
ImGui::PopFont();
147185
ImGui::End();
186+
148187
}
149188

150189
void Hero::guiInventory() {
151190
ImVec2 pos = {0,0};
152191
auto cond = ImGuiCond_Always;
153192
ImVec2 pivot = {0,0};
154193
ImGui::SetNextWindowPos(pos, cond, pivot);
155-
ImVec2 size = {165, 107};
194+
ImVec2 size = {180, 107};
156195
ImGui::SetNextWindowSize(size, cond);
157196
auto flags =
158197
ImGuiWindowFlags_NoTitleBar |
@@ -185,7 +224,7 @@ void Hero::guiInventory() {
185224
ImGui::EndTooltip();
186225
}
187226

188-
if (count == 0 || count %4 != 0)
227+
if (count == 0 || count %3 != 0)
189228
ImGui::SameLine();
190229
count ++;
191230
}
@@ -201,3 +240,7 @@ void Hero::onGui() {
201240
guiGameInfo();
202241
guiInventory();
203242
}
243+
244+
void Hero::setCamera(std::shared_ptr<CameraComponent> cam) {
245+
this->cam = cam;
246+
}

project/gui/Hero.hpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#pragma once
66

77
#include "Component.hpp"
8+
#include "CameraComponent.hpp"
89

910
class Hero : public Component {
1011
public:
@@ -14,11 +15,16 @@ class Hero : public Component {
1415

1516
bool onKey(SDL_Event &event) override;
1617
void update(float deltaTime) override;
18+
void setCamera(std::shared_ptr<CameraComponent> cam);
1719
private:
1820
void guiGameInfo();
1921
void guiSpeechBubble();
2022
void guiInventory();
2123

24+
std::shared_ptr<sre::Texture> powerbar;
25+
glm::vec2 powerbarSize;
26+
std::shared_ptr<sre::Texture> heartIcons[3];
27+
glm::vec2 heartSize;
2228
std::shared_ptr<sre::SpriteAtlas> heroSpriteAtlas;
2329
static std::map<std::string, std::shared_ptr<sre::Texture>> inventoryTexture;
2430
glm::vec2 velocity;
@@ -27,10 +33,13 @@ class Hero : public Component {
2733
float speachBubbleTimeOut = 10;
2834
std::string message = "Hi! AWSD to control.";
2935

36+
std::shared_ptr<CameraComponent> cam;
37+
3038
glm::ivec2 heroSize;
3139

3240
// hero stats
33-
int health = 10;
34-
int score = 3;
41+
int health = 3; // between 0 and 6
42+
int score = 42;
43+
float power = 0.7; // between 0.0 and 1.0
3544
std::set<std::string> inventorySet;
3645
};

project/gui/MainMenuComponent.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void MainMenuComponent::onGui() {
3838
auto winsize = r->getWindowSize();
3939
ImVec2 iWinSize(224,150);
4040

41-
ImVec2 pos ((winsize.x - iWinSize.x)/2, winsize.y/2);
41+
ImVec2 pos ((winsize.x - iWinSize.x)/2.0f, winsize.y/2.0f);
4242
auto cond = ImGuiCond_Always;
4343
ImGui::SetNextWindowPos(pos, cond);
4444
ImGui::SetNextWindowSize(iWinSize, cond);

project/gui/RPG.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,21 @@
77
#include "Hero.hpp"
88
#include "MainMenuComponent.h"
99
#include "SpriteComponent.hpp"
10+
#include "CameraComponent.hpp"
1011
#include "sre/SpriteAtlas.hpp"
1112
#define GLM_ENABLE_EXPERIMENTAL
1213
#include "glm/gtx/string_cast.hpp"
1314

1415
using namespace sre;
1516

17+
const glm::vec2 heroStartingPos(305,200);
18+
1619
RPG::RPG()
1720
:currentScene(&mainMenu)
1821
{
19-
r.setWindowSize({600,400});
22+
r.setWindowSize({600,450});
2023
r.init()
24+
.withSdlWindowFlags(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE)
2125
.build();
2226

2327
ImGuiIO& io = ImGui::GetIO();
@@ -29,7 +33,6 @@ RPG::RPG()
2933

3034
auto world = sre::Texture::create()
3135
.withFile("assets/Arkanos_0.png")
32-
.withFilterSampling(false)
3336
.build();
3437
this->world = SpriteAtlas::createSingleSprite(world,"world", {0,0});
3538

@@ -67,7 +70,8 @@ void RPG::buildMainMenu(){
6770
auto spriteComp = gameObject->addComponent<SpriteComponent>();
6871
spriteComp->setSprite(sprite);
6972

70-
mainMenu.getCamera().setWindowCoordinates();
73+
mainMenu.getCamera().setOrthographicProjection(200, -1, 1);
74+
mainMenu.getCamera().lookAt({heroStartingPos,0},{heroStartingPos,-1},{0,1,0});
7175
}
7276

7377
void RPG::buildGame(){
@@ -78,10 +82,18 @@ void RPG::buildGame(){
7882
auto spriteComp = gameObject->addComponent<SpriteComponent>();
7983
spriteComp->setSprite(sprite);
8084

81-
game.getCamera().setWindowCoordinates();
82-
8385
auto heroGameObject = game.createGameObject();
84-
heroGameObject->addComponent<Hero>();
86+
87+
auto camereObj = game.createGameObject();
88+
auto cameraComp = camereObj->addComponent<CameraComponent>();
89+
cameraComp->setCamera(&game.getCamera());
90+
game.getCamera().lookAt({heroStartingPos,0},{heroStartingPos,-1},{0,1,0});
91+
cameraComp->setSize(200);
92+
cameraComp->setTarget(heroGameObject);
93+
94+
auto h = heroGameObject->addComponent<Hero>();
95+
heroGameObject->setPosition({heroStartingPos});
96+
h->setCamera(cameraComp);
8597
}
8698

8799
void RPG::play(){

project/gui/assets/hud_heartEmpty.png

1.08 KB
Loading

project/gui/assets/hud_heartFull.png

1.13 KB
Loading

project/gui/assets/hud_heartHalf.png

1.33 KB
Loading

project/gui/assets/license.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@ https://proggyfonts.net/proggy-tiny/
1212

1313
496 pixel art icons for medieval/fantasy RPG
1414
CC0
15-
https://opengameart.org/content/496-pixel-art-icons-for-medievalfantasy-rpg
15+
https://opengameart.org/content/496-pixel-art-icons-for-medievalfantasy-rpg
16+
17+
Platformer Art Deluxe
18+
CC0
19+
https://opengameart.org/content/platformer-art-deluxe

0 commit comments

Comments
 (0)