Advertisement

October 2017 GameDev Challenge: Arcade Battle Arena!

Started by October 04, 2017 08:12 PM
38 comments, last by Endurion 6 years, 11 months ago
10 minutes ago, MarcusAseth said:

So how would bigger projects handle the rendering of a text that change shade in the specific? :P

I'm not sure how flexible SDL is to do this, but I if I could access the OpenGL context via SDL, I would create a grayscale texture with every text I need, then a shader that do one of the two things:

  1. Take the vertex data + a uniform variable indicating the color, then the shader would use the grayscale as brightness value to plot the color
  2. Take the vertex data that includes the color for each vertex, then do the same as above (brightness + color) 

The fragment shader (responsible for selecting the output color) would be something simple like:

"gl_FragColor = vec4(grayscale * r, grayscale * g, grayscale * b, alpha);"

9 minutes ago, ferreiradaselva said:

I'm not sure how flexible SDL is to do this, but I if I could access the OpenGL context via SDL, I would create a grayscale texture with every text I need, then a shader that do one of the two things:

  1. Take the vertex data + a uniform variable indicating the color, then the shader would use the grayscale as brightness value to plot the color
  2. Take the vertex data that includes the color for each vertex, then do the same as above (brightness + color) 

The fragment shader (responsible for selecting the output color) would be something simple like:

"gl_FragColor = vec4(grayscale * r, grayscale * g, grayscale * b, alpha);"

I see, thanks! :)

Advertisement

Ok, i've deceided i've met my 48 hour deadline(+/- a bit, as i wasn't keeping exact track, but several hours were lost to playing games with friends, so i think it evens out).

I'm happy with my progress, it's not quite as much as i wanted, but it both meets the requirements of this challenge, and mechanically the idea's i wanted to play out.  overall i find it decently fun, I think if i dedicated more time to ai variety and wave tuning it could be more fun.  Ultimately i'm happy with what i was able to do in my self imposed limits.  Thank you @ferreiradaselva for creating the challenge, and I hope my work can be a learning experiance for others some day.

Link to github codebase:  https://github.com/slicer4ever/TriColor-Wars 

This is a video of gameplay:

 

 

1 hour ago, ferreiradaselva said:

Content loading. I automated my build system to convert the PNG (texture atlas) to a c header containing the PNG in RGBA format. That way, I don't need to ship the executable with a *.dat or *.zip or even the PNG loose. I will do the same for sound effects.

That's an interesting approach to data packaging, personally i'm not a fan of embedding content into the binarys when possible as it means a generally longer pipeline if some of your assets are in heavy modification.

 

35 minutes ago, MarcusAseth said:

So how would bigger projects handle the rendering of a text that change shade at every draw, in the specific?

Do you mean like allocating a sequence of pre-rendered images of all the shades for a given piece of text?

The way i handle it is through bitmap fonts.  basically you load a texture with all the characters you need, and a supplimentary file which tells you where in the texture each glyph is, and supplimentary information.  

then for dynamic text strings, each frame you reconstruct a mesh buffer of the glyphs for your text, and upload them for drawing.

for static text, you can use framebuffers or manually building of a texture that encompases the static text you want on screen, this is ideally more performant, but honestly all my text rendering is done as i described above, and i've yet to find a modern platform where their was any noticable performance impact due to it.

Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

what is a mesh buffer?! :S 

This by the way is where I am right now:

Font.cpp

Spoiler

 



#include "Utility.h"
#include "Font.h"


Font::Font(std::string path, uint8_t size) :
	Path{ path }, Size{ size }, TTFFont{ nullptr }
{
	if (TTF_WasInit()) {
		OpenFont(Path.c_str(), Size);
	}
}

Font::~Font()
{
	if (TTFFont) {
		if (!TTF_WasInit()){ Util::LogConsole("fuck!!"); }
		CloseFont();
	}
}

TTF_Font* Font::GetFont()const
{
	return TTFFont;
}

Font& Font::Resize(uint8_t size)
{
	Size = size;
	if (TTFFont) { 
		CloseFont(); 
	}
	OpenFont(Path.c_str(), Size);
	return *this;
}

void Font::OpenFont(std::string path, uint8_t size)
{
	TTFFont = TTF_OpenFont(Path.c_str(), Size);
	if (!TTFFont)
	{
		Util::LogConsole(TTF_GetError());
	}
}

void Font::CloseFont()
{
	TTF_CloseFont(TTFFont);
	TTFFont = nullptr;
}

 

Button.cpp

Spoiler


#include "Button.h"



Button::Button(SDL_Window* window, std::string text, int x, int y, Font& font, SDL_Color* buttonColor) :
	Window{ window }, Text{ text }, ButtonFont{ font }, ButtonColor{ buttonColor }, Shape{x,y,0,0}
{
	ReCalculateSize();
	CenterOnPosition();
}

Button::~Button()
{
}

void Button::ReCalculateSize() 
{
	TTF_SizeText(ButtonFont.GetFont(), Text.c_str(), &Shape.w, &Shape.h);
}

void Button::CenterOnPosition()
{
	Shape.x -= Shape.w / 2;
	Shape.y -= Shape.h / 2;
}

const char* Button::GetText() const
{
	return Text.c_str();
}

const SDL_Rect & Button::GetShape() const
{
	return Shape;
}

bool Button::IsHovered() const
{
	int MouseX{}, MouseY{};
	SDL_GetMouseState(&MouseX, &MouseY);

	if (MouseX < Shape.x + Shape.w &&
		MouseX > Shape.x &&
		MouseY < Shape.y + Shape.h &&
		MouseY > Shape.y)
	{
		return true;
	}
	return false;
}

bool Button::IsPressed() const
{
	if (SDL_GetMouseState(0, 0) & SDL_BUTTON(SDL_BUTTON_LEFT))
	{
		return true;
	}
	return false;
}

SDL_Color& Button::GetColor() const
{
	return *ButtonColor;
}

void Button::SetColor(SDL_Color & color)
{
	ButtonColor = &color;
}

 

MenuState.cpp

Spoiler


#include "MenuState.h"
#include "Paths.h"
#include "Button.h"
#include "GameMode.h"
#include "SDL2\SDL.h"

MenuState::MenuState(GameMode* game, Util::WindowInfo windowInfo) :
	GameState(game, windowInfo), BubbleFont(Paths::Fonts::BUBBLEBATH, 35),
	BaseTextColor{ 165,161,141,255 }, HighlightColor{ 222,210,181,255 }
{
	PlayButton = std::make_unique<Button>(WindowInfo.Window, "Play",
										  WindowInfo.Width / 2, WindowInfo.Height / 3,
										  BubbleFont, &BaseTextColor);
}

MenuState::~MenuState()
{
}

void MenuState::Update(float deltaTime)
{
	if (PlayButton->IsHovered()) {
		//pressed
		if (PlayButton->IsPressed())		{
			Game->SetCurrentState(GameMode::EGameState::PLAY);
		}

		//hovered
		if (&PlayButton->GetColor() != &HighlightColor) {
			PlayButton->SetColor(HighlightColor);
		}													  
	}
	else {//not hovered
		if (&PlayButton->GetColor() != &BaseTextColor) {
			PlayButton->SetColor(BaseTextColor);
		}
	}

}

void MenuState::Draw(float interpolation)
{

	SDL_Surface* TempText = TTF_RenderText_Blended(BubbleFont.GetFont(), PlayButton->GetText(), PlayButton->GetColor());
	SDL_Texture* TextTexture = SDL_CreateTextureFromSurface(WindowInfo.Renderer, TempText);

	//Draw
	SDL_SetRenderDrawColor(WindowInfo.Renderer, 40, 34, 50, 255);
	SDL_RenderClear(WindowInfo.Renderer);
	SDL_RenderCopy(WindowInfo.Renderer, TextTexture, NULL, &PlayButton->GetShape());
	SDL_RenderPresent(WindowInfo.Renderer);

	//cleanup
	SDL_FreeSurface(TempText);
	SDL_DestroyTexture(TextTexture);
}

 

Next I think I'll jump into the playState. What's the first logic task? Maybe an Entity class and then derive a Tile class from Entity?  (because tile have collision too, like other entities)

Though, Should I store tiles in a separate vector<Entity*>, since they don't require updates?

Hi guys, I have my texture loading and entity mostly done, here in the image below my tiles entities neatly packed.

Now the next step should be to load a level, I guess. I am not yet sure how to handle that, never done. Should Level be a class object that I call with the path on disk of the level data? What is that data? a .txt? How do I parse the data to make it create the appropiate entity type inside the game?  

Can anyone link some good tutorials (possible C++) about the correct way to do this? I don't think I will proceed until I have it figure it out, I would only end up making a mess I'm sure.  Help! :P

6UwL8D1.png

On 8.10.2017 at 4:49 AM, MarcusAseth said:

what is a mesh buffer?! :S 

This by the way is where I am right now:

Though, Should I store tiles in a separate vector<Entity*>, since they don't require updates?

The best tip i can give you or anybody else when you dont know what do to or dont know how get it working:

 

Write down your actual code for loading and rendering fonts into the main loop directly until it actually does something: Until your text is on the screen, or your mesh renders and rotates, or your player moves and kills enemies, whatever.... For any kind of problem.

Then start making a nice api / classes with no implementation and comment out your entire your code from before and put in your api/class and use it instead. If you satisfied with your api then move the actual working code you have written so far into the api/classes. Dont go any further than that. If you are advanced you can plan a little bit for the future, but only a little bit.

You can always abstract it away later! Do not abstract it right away, even when it looks obvious.

 

To give an real world example:

Spoiler

I have written a successful business application used by 100+ clients, which had the initial requirements:

- Copy some files in already defined xml file stored somewhere on the clients machine from a non-mapped windows share into a fixed installation path on the user clients machine

- The application must be able to do this without admin user privileges, so the operative code must be executed by a WCF service which has proper rights.

- The user can trigger this operation from a normal desktop application without needing any administrative privileges whatsoever.

- It must be rock solid and must be able to update itself

 

Thats the requriment, now to we get to the actual implementation:

I created a c# console application with one class and the main() entry point only - containing all code to satisfy the base requirements without any others methods or classes. When i run that application with admin rights it worked beutifully. Of course when i run it without admin rights it crashed at that point when it wanted to write/create something  in "C:\Program files" which was the targets base directory.

 

Now i moved out all actual file and directory operation code into its own static methods and made sure that it still works and does not depend on anything. Then i created a interface "IAdminFileOperations" containing all that method signatures. After that i created a class which implements the interface and containing all the code i had already. Of course i changed all the code to use the new interface and the implementation class instead and tested it by a unit-test class.

 

Now i had to get it working without admin privileges, called by that console application - which was a pain in the ass.

So i created two additional projects: One WCF windows service, one class library. I moved the interface into the class library and moved the implementation class into the windows service. A few days later i got it working doing exactly what i wanted. Why tooked it so long? Well... WCF (Windows Communication Framework) just sucks and is one of the worst network framework thingy i ever have worked with. But well it was a required, so i got it working and was happy...

Got it more features than i had before? No i just abstracted the IO operations to the service and thats it - with a few more required classes and interfaces... just because WCF... *sigh*

 

I personally had used a simple TCP network server/client approach, but it was a requirement from the management so i had no choice :-(

 

Long story short:

Now the console application is a full blown WPF GUI Application powered by DevExpress requiring millions of dll´s... with UI, progress bar, labels, buttons, whatsoever. Just doing the same thing as before: Copying files from A to B...

Of course the initial features was expanded in great detail and now its about 50 k lines of code with tons of classes. Now it supports FTP,  SFTP and Share´s as Source and Target as well - including impersonation if needed, but only abstracted with one interface and one class for each system. Just one layer more than i had before.

But the actual code which loops over the source files and triggers the actual operations is still the same as it was before: One gigantic method (>100 lines of code) - just because it worked beutifully and their was no need to change or abstract that. If there isn´t a need, dont abstract it.

 

And yes most of it is unit-tested, but the WCF part is not...

 

Could i have planned it? Partly yes, but the planning in this case would be useless just because the initial requirements was changed so much and often that it had never matched the planning at all... Also i had no idea about WCF and had to learn it. The documentation for that was pretty bad as well...

 

One major mistake i learned from that:

Dont put any code into a static constructor! When one single exception gets thrown you are screwed and the windows service wont startup.

 

Advertisement
On 10/9/2017 at 7:31 AM, MarcusAseth said:

Now the next step should be to load a level, I guess. I am not yet sure how to handle that, never done. Should Level be a class object that I call with the path on disk of the level data? What is that data? a .txt? How do I parse the data to make it create the appropiate entity type inside the game?

There are many options possible here.

  • Make levels on Tiled, export to *.JSON and interpret using a JSON parser (which there are many online). Or export to *.CSV, which is very easy to parse without 3rd libraries.
  • Make the levels in the source code itself ¯\_(ツ)_/¯ that's what I'm doing, since the levels are small.
  • Procedural generation. 

 

On 10.10.2017 at 11:57 PM, ferreiradaselva said:

There are many options possible here.

  • Make levels on Tiled, export to *.JSON and interpret using a JSON parser (which there are many online). Or export to *.CSV, which is very easy to parse without 3rd libraries.
  • Make the levels in the source code itself ¯\_(ツ)_/¯ that's what I'm doing, since the levels are small.
  • Procedural generation. 

 

Another option is to store the level in a uncompressed PNG/BMP image.

Making levels would just require a image creation programm, like paint.net, paint, photoshop, etc. Each pixel would represent a tile. Colors or components define the index into a tilesheet.

You can even have multiple layers - just make each pixel component a layer, for example: Red are solid tiles, Green are background tiles, Blue are entities etc.

 

I personally store my levels in binary files, so i can load it without doing any parsing at all.

Of course this requires you to make a plugin for an existing editor or write your own level editor - which is not that hard.

 

I recommend when you just want to define a simple level, just use a constant array in the code to get started.

I'm probably in too. I'm using my home made Xtreme engine, which I've already used for WoA entries (and most other games on my home page).

I'm going for a second part of a Bubble Bobble clone I wrote back in DOS ages with Turbo Pascal. 

The levels are storied binary as well. If I ever see I'm going to do lots of stages I usually implement a simple editor in the game itself. A real editor helps a lot if you want to quickly test out different things.

 

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Making progress after a few evenings (Yeah i know it looks really devy, but it works great and has a stable system behind):

" rel="external">

 

Taking little baby-steps to finish a game - hopefully in time.

This topic is closed to new replies.

Advertisement