Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

1340550 Posts in 61234 Topics- by 52736 Members - Latest Member: jellyfishlion

June 17, 2018, 08:03:52 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityDevLogsTower defence game (with pixel art because why not)
Pages: [1] 2 3
Print
Author Topic: Tower defence game (with pixel art because why not)  (Read 2099 times)
Kerndog73
Level 0
**



View Profile
« on: April 17, 2018, 10:55:30 PM »

Who doesn't love a good tower defence game?

I know I do! That's why I've decided to create one of my own. This is going to be one of my biggest games yet. I'm in the design stage at the moment so I can't share any screenshots. I can however, give a vague description of the game.

  • The game chooses the maze for the player. (Similar to Bloons Tower Defence)
  • The units don't attack the towers.
  • The towers are placed on a grid. The units move along a grid.
  • The player is given as much information about the towers and units possible. (Rate of fire, damage per second, armour piercing, dodge chance, the whole shebang)
  • The damage dealt to the base is proportional to the health of the unit that reach's the base.
  • The player's only income is the gold dropped from units.

I know that's pretty vague but it should give a rough idea of the sort of game I'm going for. I have a clear vision of the final game and I've written some detailed plans. I'll spend the next few days designing and planning. I probably would have started writing code by Monday next week. I won't have any screenshots until May.

I hope at least one person is looking forward to the release!



This game has been completed. You can download it on itch.io. The game is available as a MacOS app, a Web Page and a Windows executable.
« Last Edit: June 16, 2018, 04:36:01 PM by Kerndog73 » Logged
Tusky
Level 0
***



View Profile WWW
« Reply #1 on: April 17, 2018, 11:17:14 PM »

Who doesn't love a good tower defence game?

Nobody.

I'll look forward to seeing what you come up with  Smiley
Logged
Kerndog73
Level 0
**



View Profile
« Reply #2 on: April 18, 2018, 07:31:51 PM »

I just completely changed the towers and how they are upgraded.

The first upgrade of a tower is a choice upgrade. For example, the Archer can be upgraded to a group of crappy archers or one very good Archer. These two choices have almost equivalent effects on the battle field but they have very different stats. All further upgrades will just increase the stats slightly. I'm not gonna go all out on choices like Bloons Tower Defence does.

I'm giving the player choices because I want the player to think. I want the player to look at the stats of the towers and look at the stats of the units to determine the best course of action.

This is a thinking game.
Logged
Kerndog73
Level 0
**



View Profile
« Reply #3 on: April 19, 2018, 06:57:30 PM »

This is what the UI will look like.



Pixel art just looks fantastic, doesn't it! Especially at an integer scale factor.

The four boxes with drawings in them are the towers. In case my drawing is worse than I thought, there's an arrow, a boulder, a snowflake and a flame. Below the four boxes is the Stats Area. Clicking on a tower or unit will show the stats here. Hovering over a tower in the menu will also show the stats. Towers can be upgraded and sold by clicking the green and red buttons. The space below those buttons will be used for choice upgrades. For example, a Catapult can be upgraded to a Poison Catapult or an Explosive Catapult. The dark grey rectangle is where the game will be. The game consists of a map of 32x21 tiles with each tile being 16x16 pixels.

The UI isn't very dynamic so I'll first render an image similar to the one above and then render text on top of that. I don't want to fluff around with trying to create a TTF file and then loading that into SDL_TTF and then fighting the library to make it render at the right resolution. Rendering the text myself is way more fun! Also, the UI code that I write for this game could be reused for future games. This is the first one of my games with an actual UI.



I think I've finished planning. I might just have a final think about the details and then start on the text renderer. I haven't written code in two months. I can't wait to start programming again! Programming is great, isn't it!
Logged
Kerndog73
Level 0
**



View Profile
« Reply #4 on: April 20, 2018, 05:04:28 PM »

That two month break from programming has had a much bigger impact than I thought. I've forgotten how to make games. I don't even remember how to open a window. I created a new Xcode project and I don't even know where to begin. When I started my last game, I knew exactly what I was doing. I just started creating files and filling them with code and then I was done.

I stopped making games for two months because I ran out of ideas for games. I didn't know what to make. This is truly frightening. I can't stop making games or I'll lose all of the knowledge that I have accumulated over the years. What if I come back after a year and ask myself "What's a linked list?".



I suppose I'll have to simplify the project now. I'll make a bare minmum tower defence game. One type of tower and one type of unit. When I've done that, I'll add more towers and units with complex animations and detailed interfaces.

Don't ever take a break from programming. You will regret it.
Logged
Kerndog73
Level 0
**



View Profile
« Reply #5 on: April 21, 2018, 12:45:16 AM »

I might have been a bit dramatic in that last post!  Facepalm

Since that last post, I wrote 1091 lines in 44 files. Everything just sorta came back!  Shrug

But I still regret taking a break from programming.



This is my first devlog and I seem to be treating it like a blog or a diary. I hope at least one person is entertained by my nonsense. Cheesy
Logged
Kerndog73
Level 0
**



View Profile
« Reply #6 on: April 21, 2018, 05:29:30 PM »

The prototype game is nearly there. I’ve got units that move along a set path. Towers aim at the unit closest to the base and fire when their ROF permits. Today I’ll  draw some sprites for the prototype and then upload some gifs and screenshots. After that I’ll implement splash towers, effects (poison and slow), tunnels and the UI. That dam UI is gonna be the most difficult part of the project. I HATE UI PROGRAMMING.
Logged
Kerndog73
Level 0
**



View Profile
« Reply #7 on: April 22, 2018, 04:53:40 AM »

I've created some placeholder art. Here's the spritesheet.



And here's a gif of the placeholder animations in action.



That looks awful!

I didn't even attempt to do a walking animation, they just wave their arms in front of themselves!

I think the only good sprite there is the path. It looks like gravel and it repeats nicely. I was originally going to draw orcs, ogres, knights, goblins, peasants, etc but I don't think I can create animations for all of those. As you might be able to tell from the spritesheet, I have to do four separate animations for each direction that the unit is moving in because I didn't want to just draw heads and shoulders. I don't think I'm going to be able to draw that many frames for complex figures like ogres and goblins. I'll have to draw something more simple like a robot.
Logged
Kerndog73
Level 0
**



View Profile
« Reply #8 on: April 22, 2018, 05:42:48 PM »

I decided that a stickman waving is arms around wasn't gonna cut it. So I decided to draw silly looking robots that balance on one wheel. I was originally going to make the map 32x21 tiles but I think that's a bit too big.



I'm not sure why that gif doesn't repeat as well as the other one. The map is too big. What am I gonna do with all of those tiles? The robots are too small to see. So I halved the size of the map to 16x10.



I think that looks much better and the gif even repeats properly. Hurray!   Toast Left Grin Toast Right I will have to adjust the UI design because I've just changed the pixel size of the map by 16 pixels. I had to round down 21/2 to 10.



I've created towers but it's kind of hard to test them without seeing them so now I'm going to draw some placeholder art for the tower.
Logged
Kerndog73
Level 0
**



View Profile
« Reply #9 on: April 22, 2018, 11:30:09 PM »

I couldn't decide if I liked the vertical gradient or the radial gradient so I decided to take screenshots of the two and compare them side by side. Out of sheer luck, the robots and the tower happened to be in the same place on both screenshots! HOLY CRAP!!! It's not that unlikely, the framerate is 15 and everything repeats itself every 3 seconds. So it's a 1/45 chance (maybe, probability has always seemed kind of wishy-washy to me) that this will happen.

Then I made a GIF



I still can't decide.
Logged
Kerndog73
Level 0
**



View Profile
« Reply #10 on: April 23, 2018, 03:47:58 AM »



« Last Edit: June 06, 2018, 03:33:34 AM by Kerndog73 » Logged
Kerndog73
Level 0
**



View Profile
« Reply #11 on: April 25, 2018, 02:01:01 AM »

I've done a lot of work on the deserialization system and some general refactoring of the game state. Maps are stored in files. Levels are stored in files. Towers are stored in files. The names of sound files are stored in a file. There are lots of things happening in files! I'm using http://jsonnet.org for representing the towers and levels in files. Jsonnet is a functional language that compiles to JSON. I think it's excellent. It solves all of the problems that YAML was meant to solve (plus more) without all of the problems of YAML. There are no good YAML libraries written in C++. There are so many excellent JSON libraries in so many languages that it's hard not to use JSON.

Ok, that kind of turned into a bit of a rant. The point I was trying to make is that we should all download Jsonnet and hate YAML. Anyway, I drew a cannon.



I still haven't gotten around to creating projectiles for the towers. I should also create an explosion animation for when the robots are destroyed. And a spawning animation for when the robots appear. I still need to implement splash towers and effects. There's still a lot to do on this game.
Logged
Kerndog73
Level 0
**



View Profile
« Reply #12 on: April 26, 2018, 12:08:22 AM »

I've created animations for projectiles, unit destruction and sounds for unit destruction.



The rest of this post is just about game code

I can't believe how easy it was to add the animations. Rendering a new set of animations has never been this easy before. I've been using OpenGL 4.1 for years and I've created various abstractions for each of my games. For this game, I created an abstraction similar to the old school immediate mode OpenGL tailored for textured quads.

The first layer of the abstraction is a series of RAII classes for managing OpenGL objects. The RAII classes aren't a full wrapper around OpenGL, they just manage the lifetime of objects. There are also factory functions for creating some of the objects. For example, there is makeTexture2D factory that takes a surface and texture parameters to create a Texture object.

The second layer of abstraction is the quad renderer. The quad renderer takes these data structures as input.

Code:
struct Vertex {
  glm::vec3 pos;
  glm::vec2 texCoord;
};
using Quad = std::array<Vertex, 4>;

struct QuadRange {
  size_t begin;
  size_t end;
};

struct RenderParams {
  glm::mat3 viewProj = {};
  TextureID tex = 0;
  glm::vec4 color = glm::vec4(1.0f);
};

The renderer manages the shaders, textures, element buffer and array buffer. The user just provides an array of quads and a RenderParams object to describe how all of the quads are rendered. The renderer is very similar to this:

Code:
class Renderer {
public:
  void init()
  void quit();
  
  TextureID addTexture(GL::Texture2D &&);
  TextureID addTexture(const Surface &, GL::TexParams2D);
  TextureID addTexture(std::string_view, GL::TexParams2D);
  
  bool resizeQuadBuf(size_t);
  bool writeQuads(QuadRange, const Quad *);
  void render(QuadRange, const RenderParams &);

private:
  //textures, shaders, etc
};

The final layer of abstraction is what is used by the actual game. This is the QuadWriter. The QuadWriter stores an array of Quads and provides functions for pushing quads onto the array, setting the positions, setting the texture coordinates, setting the depth and setting the RenderParams for a section of quads. It's a pleasure to use!

Code:
class QuadWriter {
public:
  void clear();
  
  void section(const RenderParams &);
  void sectionReserve(size_t);
  
  Quad &quad();
  
  void depth(float);
  
  void tilePos(glm::vec2, glm::vec2 = {1.0f, 1.0f});
  void rotTilePos(float, glm::vec2, glm::vec2 = {1.0f, 1.0f});
  
  void tileTex(glm::vec2, glm::vec2);
  void tileTex(Math::RectPP<float>);
  
  void render(Renderer &) const;
};

All I have to do is pass a reference to the QuadWriter to each rendering system and they push some quads. Then after all of the rendering systems have pushed all of their quads, the quads are rendered and the QuadWriter is cleared. It's pretty quick and super easy to use. I love this thing!
Logged
Kerndog73
Level 0
**



View Profile
« Reply #13 on: April 29, 2018, 06:20:45 PM »

I’ve implemented splash towers. Splash towers deal splash damage to units in an area when they shoot a unit. Splash towers also give an effect to units in an area. I’ve only implemented two effects, poison and slow. Here we have a splash tower dealing a large amount of damage and giving a poison effect.



The poison effect deals a percent of a units full health as damage per second for a short duration. The poison effect in the GIF is 20% damage per second for 5 seconds. I think I’m going to spend the rest of the day drawing animations for towers.



School holidays end tomorrow so progress is going to be very slow from now on.
Logged
Kerndog73
Level 0
**



View Profile
« Reply #14 on: May 02, 2018, 05:41:04 PM »



This text renderer was actually surprisingly easy to make. The meat of the class is just 14 lines! I made the 5x8 ASCII font myself. I think it looks pretty cool.



I seem to be a bit out of my league on these forums. Everyone else seems to be posting about big 3D masterpieces and here I am celebrating the fact that I can now render low-resolution monospaced ASCII text.

It's kind of sad.
Logged
Tusky
Level 0
***



View Profile WWW
« Reply #15 on: May 02, 2018, 09:43:18 PM »

It's kind of sad.

Nah I don't think you've got any less right to be posting about your progress here that anyone else tbh.

Are you making your own engine for this? What language?
Logged
Kerndog73
Level 0
**



View Profile
« Reply #16 on: May 02, 2018, 10:11:56 PM »

Quote
Nah I don't think you've got any less right to be posting about your progress here that anyone else tbh.

Thanks Tusky, that really means a lot to me. I'm not gonna stop posting. I will post until my game is done.

Quote
Are you making your own engine for this? What language?

I've been working on my own game engine for quite a while. Every time I finish a game, I take some useful code, clean it up and put it in the game engine for use in future games. About 80% of the game engine was originally in a game.

My game engine is on Github if you want to check it out. https://github.com/Kerndog73/Simpleton-Engine It's a header-only C++ library. I use SDL2 for creating windows, taking keyboard input, etc. I use OpenGL for rendering. My game engine includes code that abstracts both of these libraries. I described in a previous post that I can just pass some textured quads to my game engine and it handles all of the OpenGL stuff for me.

I use this ECS framework https://github.com/skypjack/entt for implementing the game logic. I use this JSON parser https://github.com/nlohmann/json for reading level files. I use this programming language http://jsonnet.org/ which compiles into JSON to define levels, entities, and other game logic stuff.

The game engine is very well documented (most functions and classes have a brief documentation comment) but it's more of a library than a framework so you don't need to understand the whole thing to use it.
Logged
Kerndog73
Level 0
**



View Profile
« Reply #17 on: May 03, 2018, 05:53:59 PM »

I made a mistake in my math. I didn't multiply the coordinates of rotated quads by the square root of 2 so they were a little smaller than they should have been. This only affected the rotating parts of the towers and projectiles. I only noticed it after zooming in on a screenshot. If I hadn't done that, I may have never noticed! Here's a GIF that shows the difference. Small is how they were, large is how they should be.



Here's the actual code after I corrected it.

Code:
const glm::vec2 halfSize = size * 0.5f;
const glm::vec2 topRight = {
  glm::root_two<float>() * halfSize.x * std::cos(angle + glm::quarter_pi<float>()),
  glm::root_two<float>() * halfSize.y * std::sin(angle + glm::quarter_pi<float>())
};
const glm::vec2 topLeft = {-topRight.y, topRight.x};
const glm::vec2 botLeft = -topRight;
const glm::vec2 botRight = -topLeft;
const glm::vec2 shift = pos + halfSize;

Who else thinks that variables should be immutable by default and we should make them mutable with a mut keyword? Rust does this but rust also has some weird stuff like a borrow checker thingy.
Logged
Kerndog73
Level 0
**



View Profile
« Reply #18 on: May 04, 2018, 09:20:46 PM »

I added lasers.



Lasers have a long range and fire continuously. You can see in the gif that the laser beam passes under the iceball tower which looks a little strange. Getting everything the right depth is quite challenging. The beam has to be under the laser tower and over all other towers and it has to be under the unit. I really don't know how to order everything!

The animations are a bit messed up. The animation system is tailored for towers that fire projectiles so I had to hack around with it to get it to work with beam towers. It seems to work but it might need to be re-written when I add flamethrowers. Yes, you read that right, FLAMETHROWERS! A flamethrower essentially an animated laser with splash damage.

I also allowed the text renderer to handle whitespace characters like carriage returns, tabs, vertical tabs, newlines, and backspaces. Characters aren't erased when you backspace so you can make weird looking characters by rendering over previous characters. The last line of text was created by rendering this "Deadpal\b\bool". I can't imagine ever using backspace but it's there if I need it!
Logged
Kerndog73
Level 0
**



View Profile
« Reply #19 on: May 06, 2018, 02:43:08 AM »

It might not look like I've done much...



...but I overhauled all of the tower systems and components. I realized that the difference between a beam tower (laser) and a projectile tower (blaster) is simply the animation. I also realized that the difference between a splash tower (explosive cannon) and a turret tower (blaster) is simply the damage dealt to units. So I separated the animation systems into projectile animation and beam animation. I also separated the damage systems into splash damage and turret (I couldn't think of a better name than turret and now it's all over the code base!) damage systems. This made the systems much smaller and cleaner. I'm still yet to implement animated beams because if you look at the laser, it doesn't animate after it's locked onto a target. I need animated beams if I'm going to implement a flamethrower.

I might also create aura towers. Aura towers do continuous damage to all units within range at the same time. I'm not sure how aura towers will fit into the beam, projectile, splash, turret system I have. I'll have to think about that.

I've almost created all of the towers I need. I planned on having 4 families of 3 towers. I already have 2 + 2/3 families. Here they are:

blaster -> laser -> plasma
cannon -> explosive cannon -> poison cannon
snowball -> iceball -> (ice aura perhaps?)

The blaster is upgraded to the laser and the laser is upgraded to the plasma. I was originally going to have choice upgrades. So every time the player upgrades, they have a choice between two towers, each with their own pros and cons. That's just too much work. I would have to draw so many towers and implement so many unique game mechanics. Drawing just 12 towers is hard enough.
Logged
Pages: [1] 2 3
Print
Jump to:  

Theme orange-lt created by panic