Jump to content
  • Advertisement

OpenGL Tower Defense Indie Game Dev Blog #1: 3D Models and Pathfinding

EddieK

1434 views

About the Game

As you probably have guessed from the title, the game I'm working on is a Tower Defense type of game. At this point I'm still not sure what theme it's going to be in, but I think I will go with military based theme. The game itself is inspired by Red Alert, Robo Defense and Kingdom Rush. For development side of things I'm using Java/Kotlin (mostly Kotlin) + OpenGL and LWJGL with the IntellJ IDEA editor.

3D Models

In the last couple of weeks I've been learning how to make 3D models using Blender. After few days of modelling I got hang of the basics and could model few simple trees, turrets and a car which I then imported into the game "engine".  Here are few screenshots of the models that I have created during those days:

turret

turretScreenshot from 2018-05-14 19-58-12

car.png

 

Pathfinding

I have programmed a pathfinding management system, which uses flood-fill pathfinding algorithm to calculate where the enemies have to go. The way it works is pretty simple. You start by splitting your game map into square nodes and then generating a gradient map which will tell how far away the current node is from the target node. To do this, you firstly start at the target node, assign its value to 0, then for all the neighboring nodes increment their value by 1, or whatever number you want, as long as its a positive number. If the neighboring node is non-collidable, assign its value to something very large, like 999999.

To get the path from the start node to the current node you start at the start node, and select its neighboring node with the lowest value. Then for that selected node, do the same process until you reach node with the value of 0, which will mean that you have reached your target node.

This is how the gradient map looks in my game:

pathfinding1.png

 

Here you can see the numbers at the center of each node which represent its value. The cars are moving towards the surrounding nodes which have the lowest values until they reach 0, that's when they stop.

Okey, so why did I use this method instead of the famous A* algorithm? First of all. This is heck of a lot faster. Instead of always calculating a path each frame for each entity. You just generate the gradient map once, and update it every time an object is placed on the map. The drawback of this method is that all the entities can only go to a single target destination. If you want multiple target destinations, you will have to recalculate the gradient map with different target nodes.

Gameplay

There's not much of a gameplay at this stage of development. As of now all you can do is place turrets, watch them shoot the enemies and that's pretty much it. Nonetheless this is the gameplay footage:

 

 

Twitter: https://twitter.com/extrabitgames
Facebook: https://www.facebook.com/extrabitgames
Website: http://extrabitgames.com

My website: http://extrabitgames.com



12 Comments


Recommended Comments

This is looking very good already! You can do it as part of the gamedev challenge too, there are several of us making tower defence games at the moment. :)

Share this comment


Link to comment
2 hours ago, lawnjelly said:

This is looking very good already! You can do it as part of the gamedev challenge too, there are several of us making tower defence games at the moment. :)

Thank you!

Oh I didn't know there was a challenge like this. Is there a link in which I could read more about this? 

Share this comment


Link to comment

Is just a bit of fun, but I don't see why you can't put yours as an entry even if you are planning on selling your game after. Rutin, Awoken, Dexter and I are doing games I know of so far. :)

Share this comment


Link to comment
43 minutes ago, lawnjelly said:

Is just a bit of fun, but I don't see why you can't put yours as an entry even if you are planning on selling your game after. Rutin, Awoken, Dexter and I are doing games I know of so far. :)

Oh sounds very cool :) I just don't know if I will be able to finish this game by the time the submission date ends. Though I could try making a minimal viable product and submitting that. And then continue working on the game after submission. Anyways, thanks for letting me know. This community is so friendly :D

Share this comment


Link to comment
1 hour ago, EddieK said:

Oh sounds very cool :) I just don't know if I will be able to finish this game by the time the submission date ends. Though I could try making a minimal viable product and submitting that. And then continue working on the game after submission. Anyways, thanks for letting me know. This community is so friendly :D

If you do meet the minimum requirements for the challenge you can earn yourself the 'Tower Defence Badge'!  

Great job by the way.  Your turning mechanism is very fluid.  I also like the military theme you're going with.

Share this comment


Link to comment
1 hour ago, Awoken said:

If you do meet the minimum requirements for the challenge you can earn yourself the 'Tower Defence Badge'!  

Great job by the way.  Your turning mechanism is very fluid.  I also like the military theme you're going with.

Thanks! I will certainly try to get my game submitted there :)

Share this comment


Link to comment

Awesome TD development bro ^_^y It's nice to know your using KOTLIN... I'm learning the language but on early stage.

Share this comment


Link to comment
37 minutes ago, DexterZ101 said:

Awesome TD development bro ^_^y It's nice to know your using KOTLIN... I'm learning the language but on early stage.

Thanks! I've have been using Java for few years now and then decided to switch to Kotlin like a month ago. And all I can is that it is AWESOME :D Less boilerplate code, operator overloading (especially useful in game dev) and many more things which make programming faster. The only thing that I don't really get is the whole thing about non-nullable objects. I mean I understand how it works, but there are lots of parts in my code where I need to have a null object referance. Anyways, good luck with learning! It is really a great and modern language :)

Share this comment


Link to comment

I really like the art work! :) You should be able to meet the min. requirements easily before the due date. I hope you submit an entry! :) Great work!

Share this comment


Link to comment
16 minutes ago, Rutin said:

I really like the art work!  You should be able to meet the min. requirements easily before the due date. I hope you submit an entry! Great work!

Wow, thanks! Didn't expect to get such a positive feedback :) I will try to submit an entry, so I better go back to work now :D 

Share this comment


Link to comment

I found the pathfinding part very interesting!

By the way, which Red Alert did you take your inspiration from? I'm certainly not a huge fan of Command & Conquer and Red Alert :P

Share this comment


Link to comment
EddieK

Posted (edited)

Just wanted to thank you guys for all the kind feedback, you guys are the best!

40 minutes ago, thecheeselover said:

I found the pathfinding part very interesting!

By the way, which Red Alert did you take your inspiration from? I'm certainly not a huge fan of Command & Conquer and Red Alert :P

Thank you! Although I have played all of the Red Alert installments, I think my inspiration comes from the original Red Alert which I played on my PS1 :D I'm actually thinking of making tesla towers inside my game, just because I loved them in Red Alert so much :D

Edited by EddieK

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
  • Advertisement
  • Blog Entries

  • Similar Content

    • By phil67rpg
      well rutin has helped with this problem, but I wanted to get more input. I am still working on my rotation algorithm. I want my bullet sprite to rotate around my plane sprite and shoot in the same direction as my plane is facing.
      glTexCoord3f(0.0f, 0.0f, 0.0f); glVertex3f(cos(angle) - sin(angle), sin(angle) + cos(angle), 0.0f); glTexCoord3f(1.0f, 0.0f, 0.0f); glVertex3f(cos(angle) - sin(angle), sin(angle) + cos(angle), 0.0f); glTexCoord3f(1.0f, 1.0f, 0.0f); glVertex3f(cos(angle) - sin(angle), sin(angle) + cos(angle), 0.0f); glTexCoord3f(0.0f, 1.0f, 0.0f); glVertex3f(cos(angle) - sin(angle), sin(angle) + cos(angle), 0.0f); glEnd(); here is the code I am using.
    • By Chrispikula
      So I'm getting to the point in my engine design that I'm trying to implement some dynamic menus.  It's going well, until I've hit a recent conceptual stumbling block that I'm not how to sure to get around.  It has to do with drawing resizable, internally scrollable windows inside each monitor.
      Some background first.
      I'm creating a multi-monitor capable game, so I needed to roll my own GUI.  The window & menu system works, for fixed sized windows.  My menus are all made many sprites, utilizing DirectXTK SpriteBatch, and text via SpriteFont.  I load the images using WICTextureLoader. 
      For the case where I have activated elements in a window exceed the size of the window, that's okay.  They need to be visible, and there's only one active element at a time.  The problem comes with hiding passive elements as they are scrolled out of their parent window, and then drawn outside of it.  Also of note:  I have a *single* application drawing to all of the monitors, not multiple applications drawing to multiple monitors.  So solutions based around options that use the singleton pattern are not workable.  (This, sadly, omits most GUI frameworks).
      I've looked at using viewports, but I can't seem to get them to work properly when I'm dealing with multi-monitor displays, especially when the monitors have different resolutions, and are not aligned perfectly.  I'm not even sure where to begin if I have overlapping viewports, ie, overlapping windows.
      Should I keep struggling with viewports, or should I look into a way of dynamically clipping the images/text/sprites as they are edged out of the windows?  If so, what is such a technique called, and where can I read up more on it?
      Or am I missing a forest for the trees, and there's an easy solution to my problem that I've overlooked?
       
    • By Josheir
      I have rewritten this function a few times now and I am having trouble getting every other row to have the triangles face the reverse direction.  The image enclosed demonstrates the faulty behavior which includes only one row facing the reversed direction.  
       I am also confused by how many indexes I should have for the g_vertex_buffer_data_land variable, could someone show me a breakdown like : 18 vertices times 2 sets  times 8 columns times 8 depth.
      In another post fleabay mentioned I was not setting a VAO in core profile, however It seems to be.  
      here is the code:
       
      float* getVertices(void) { //using defines int incol = _colus; int depth = _depth; int i = 0; float scaleit = .5; float tempdepth = 0; int startindexat = 0; int counter = 0; int secondcounter = 0; //for (; (tempdepth+1) <= (depth);) //don't forget to change this back! for (int q=0;q<3;q++) { //odd rows for (int col = 0; (col+1) <= (incol ); col++) { GLfloat matrix1[3][3] = { {(col + 1),0,(tempdepth)},{ (col),0,(tempdepth)}, {(col),0,(tempdepth + 1) } }; // //vertex 1 g_vertex_buffer_data_land[startindexat + 0 + counter] = matrix1[0][0] * scaleit; g_vertex_buffer_data_land[startindexat + 1 + counter] = matrix1[0][1] * scaleit; g_vertex_buffer_data_land[startindexat + 2 + counter] = matrix1[0][2] * scaleit; //vertex 2 g_vertex_buffer_data_land[startindexat + 3 + counter] = matrix1[1][0] * scaleit; g_vertex_buffer_data_land[startindexat + 4 + counter] = matrix1[1][1] * scaleit; g_vertex_buffer_data_land[startindexat + 5 + counter] = matrix1[1][2] * scaleit; g_vertex_buffer_data_land[startindexat + 6 + counter] = matrix1[2][0] * scaleit; g_vertex_buffer_data_land[startindexat + 7 + counter] = matrix1[2][1] * scaleit; g_vertex_buffer_data_land[startindexat + 8 + counter] = matrix1[2][2] * scaleit; int matrix2[3][3] = { { (col + 1),0,(tempdepth + 1)},{ (col + 1),0,(tempdepth)}, {(col),0,(tempdepth + 1) } }; g_vertex_buffer_data_land[startindexat + 9 + counter] = matrix2[0][0] * scaleit; g_vertex_buffer_data_land[startindexat + 10 + counter] = matrix2[0][1] * scaleit; g_vertex_buffer_data_land[startindexat + 11 + counter] = matrix2[0][2] * scaleit; g_vertex_buffer_data_land[startindexat + 12 + counter] = matrix2[1][0] * scaleit; g_vertex_buffer_data_land[startindexat + 13 + counter] = matrix2[1][1] * scaleit; g_vertex_buffer_data_land[startindexat + 14 + counter] = matrix2[1][2] * scaleit; g_vertex_buffer_data_land[startindexat + 15 + counter] = matrix2[2][0] * scaleit; g_vertex_buffer_data_land[startindexat + 16 + counter] = matrix2[2][1] * scaleit; g_vertex_buffer_data_land[startindexat + 17 + counter] = matrix2[2][2] * scaleit; counter = counter + 18; }//end col startindexat = 17 + counter+ 1; for (int col2 = 0; (col2+1) <= (incol); col2++) { //first triangle : even rows GLfloat matrix3[3][3] = { {(col2 + 1) ,0,(tempdepth + 2)} , {(col2 + 1),0,(tempdepth + 1)}, {(col2),0,(tempdepth +1)} }; // //vertex 1 g_vertex_buffer_data_land[(startindexat + secondcounter)] = matrix3[0][0] * scaleit; g_vertex_buffer_data_land[(startindexat + 1 + secondcounter)] = matrix3[0][1] * scaleit; g_vertex_buffer_data_land[(startindexat + 2 + secondcounter)] = matrix3[0][2] * scaleit; //vertex 2 g_vertex_buffer_data_land[(startindexat + 3 + secondcounter)] = matrix3[1][0] * scaleit; g_vertex_buffer_data_land[(startindexat + 4 + secondcounter)] = matrix3[1][1] * scaleit; g_vertex_buffer_data_land[(startindexat + 5 + secondcounter)] = matrix3[1][2] * scaleit; g_vertex_buffer_data_land[(startindexat + 6 + secondcounter)] = matrix3[2][0] * scaleit; g_vertex_buffer_data_land[(startindexat + 7 + secondcounter)] = matrix3[2][1] * scaleit; g_vertex_buffer_data_land[(startindexat + 8 + secondcounter)] = matrix3[2][2] * scaleit; // even (2) int matrix4[3][3] = { {(col2 + 1),0,(tempdepth+ 2)},{ (col2),0,(tempdepth+ 1)}, {(col2),0,(tempdepth + 2) } }; g_vertex_buffer_data_land[(startindexat+9 + secondcounter)] = matrix4[0][0] * scaleit; g_vertex_buffer_data_land[(startindexat+10 + secondcounter)] = matrix4[0][1] * scaleit; g_vertex_buffer_data_land[(startindexat+11 + secondcounter)] = matrix4[0][2] * scaleit; g_vertex_buffer_data_land[(startindexat+12 + secondcounter)] = matrix4[1][0] * scaleit; g_vertex_buffer_data_land[(startindexat+13 + secondcounter)] = matrix4[1][1] * scaleit; g_vertex_buffer_data_land[(startindexat+14 + secondcounter)] = matrix4[1][2] * scaleit; g_vertex_buffer_data_land[(startindexat+15 + secondcounter)] = matrix4[2][0] * scaleit; g_vertex_buffer_data_land[(startindexat+16 + secondcounter)] = matrix4[2][1] * scaleit; g_vertex_buffer_data_land[(startindexat+17 + secondcounter)] = matrix4[2][2] * scaleit; //one column of 4 triangles //(three vetices per triangle) secondcounter = secondcounter + 18; } startindexat = 17 + secondcounter + 1; tempdepth = tempdepth - 1; } return gvertices; }  
      I am hoping someone might have the experience to help me solve this problem.  Or, what could I check and do I need to show more repo code? 
       
      Thank you,
      Josheir

    • By Novakin
      HI everyone
        We are looking for a game designer to assist with creating a game. It is a 3D first/third person battle simulator. Its set in the Viking age in Norway and we want to create a brutal but fun game with focus game mechanics. We would like to have a stamina system that is linked to a weapon and armour weight system. This system will require management from the player if they hope to survive. I have a rough GDD but I need a game designer to re write it and make it better. This project is intended to be commerical so if all goes well, you will recieve a share. You will also be doing other game design jobs throught the project. We have a handful of other devs that will be working on this, 3d artists, a programmer and concept. If you are reading this and your not a game designer but want to be involved please message me as we are still looking for other devs and artists but we cant start until the gdd is complete.
       
      thank you
    • By Servant of the Lord
      I have a texture I'm reading from like this:
      vec4 diffuseFrag = texture2D(DiffuseMap, fDiffuseCoord); Sometimes, for special effects, I'd actually like to do something this:
      vec4 uvFrag = texture2D(UVMap, fUVCoord); vec4 diffuseFrag = texture2D(DiffuseMap, uvFrag.rg); ...basically, I'm using a texture's Red and Green color channels to store the frag coordinates I want to read from DiffuseMap.
      My probably is, both the UV map and the Diffuse map are spritesheets with multiple images in them. This means, I'm actually wanting uvFrag.rg's (0-1) texcoord to be multiplied against the *subportion* of the texture that all four vertices of my fDiffuseCoord are referring to.
      Something like: 
      vec4 uvFrag = texture2D(UVMap, fUVCoord).rg; vec4 upperLeftOfSubrect = ...; vec4 bottomRightOfSubrect = ...; vec4 subrectSize = (bottomRightOfSubrect - upperLeftOfSubrect); uvFrag = upperLeftOfSubrect + (uvFrag * range); vec4 diffuseFrag = texture2D(DiffuseMap, uvFrag.rg);  
      Where my mind is going blank is, how can I get upperLeftOfSubrect / bottomRightOfSubrect, without bloating my vertex struct further with additional attributes?
      It mentally trips me up that I'll have to copy upperLeftOfSubrect / bottomRightOfSubrect into all four of my vertices... and triply annoys me because I'm already passing them in as fDiffuseCoord (just spread between different vertices).
      Is there a simple solution to this that I'm missing?
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!