Jump to content
  • Advertisement

Search the Community

Showing results for tags 'Java'.

The search index is currently processing. Current results may not be complete.


More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Categories

  • Audio
    • Music and Sound FX
  • Business
    • Business and Law
    • Career Development
    • Production and Management
  • Game Design
    • Game Design and Theory
    • Writing for Games
    • UX for Games
  • Industry
    • Interviews
    • Event Coverage
  • Programming
    • Artificial Intelligence
    • General and Gameplay Programming
    • Graphics and GPU Programming
    • Engines and Middleware
    • Math and Physics
    • Networking and Multiplayer
  • Visual Arts
  • Archive

Categories

  • Audio
  • Visual Arts
  • Programming
  • Writing

Categories

  • Game Developers Conference
    • GDC 2017
    • GDC 2018
  • Power-Up Digital Games Conference
    • PDGC I: Words of Wisdom
    • PDGC II: The Devs Strike Back
    • PDGC III: Syntax Error

Forums

  • Audio
    • Music and Sound FX
  • Business
    • Games Career Development
    • Production and Management
    • Games Business and Law
  • Game Design
    • Game Design and Theory
    • Writing for Games
  • Programming
    • Artificial Intelligence
    • Engines and Middleware
    • General and Gameplay Programming
    • Graphics and GPU Programming
    • Math and Physics
    • Networking and Multiplayer
  • Visual Arts
    • 2D and 3D Art
    • Critique and Feedback
  • Community
    • GameDev Challenges
    • GDNet+ Member Forum
    • GDNet Lounge
    • GDNet Comments, Suggestions, and Ideas
    • Coding Horrors
    • Your Announcements
    • Hobby Project Classifieds
    • Indie Showcase
    • Article Writing
  • Affiliates
    • NeHe Productions
    • AngelCode
  • Topical
    • Virtual and Augmented Reality
    • News
  • Workshops
    • C# Workshop
    • CPP Workshop
    • Freehand Drawing Workshop
    • Hands-On Interactive Game Development
    • SICP Workshop
    • XNA 4.0 Workshop
  • Archive
    • Topical
    • Affiliates
    • Contests
    • Technical
  • GameDev Challenges's Topics
  • For Beginners's Forum

Calendars

  • Community Calendar
  • Games Industry Events
  • Game Jams
  • GameDev Challenges's Schedule

Blogs

There are no results to display.

There are no results to display.

Product Groups

  • GDNet+
  • Advertisements
  • GameDev Gear

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


About Me


Website


Role


Twitter


Github


Twitch


Steam

Found 90 results

  1. This is linked to another question that I asked here a couple of days ago: I'm looking at making a client-server game with a game server programmed in Java. The game will be a 2D turn-based game (like a board game), with a maximum of around 50-100 games going on at any one time. So, the performance requirements are not very high. The reason I would like to use Java for the server are because I already have some familiarity with it and I would like the server to not be tied to one particular platform. I would also like to design it so that the client interface to the server is as generic as possible, so that the same server could be used with multiple different clients. For example, there might be a web-based client, or someone else might design a stand-alone 3D client application later on, using the same server. So, I am looking for some advice on where to start with this, as I have very little experience with coding servers. I was planning to use web sockets for the client-server connection, which apparently uses Java EE (Enterprise Edition), which seems to require the use of the GlassFish server. However, I have been advised that a fully-fledged application server, like GlassFish, may be overkill for a game server. So, here are my questions: Should I use something like GlassFish? Does it makes sense for the type of game server I am describing? If not, then what sort of networking protocol/library would experienced Java game designers recommend? Are there any existing, general-purpose Java game servers that exist, which I might be able to use as a starting point? (Or even free software/open-source client-server games?) Or, should I look at coding my own game server from scratch? In which case, again, what sort of connection type/library would be recommended? Does anyone know of any suitable introductory tutorials that deal with how to make this sort of game server in Java? I guess my priority is probably minimizing the learning curve and the amount of time/effort involved, over performance. How much effort is this sort of undertaking going to require? Thanks in advance! :-)
  2. So, I developed an engine a while back following ThinMatrix's tutorials and it worked perfectly. However, upon trying to create my own simple lightweight game engine from scratch, I hit a snag. I created an engine that only wants to render my specified background color, and nothing else. I first tried to render just one cube, and when that failed I figured that i probably just had the incorrect coordinates set, so I went and generated a hundred random cubes... Nothing. Not even a framerate drop. So I figure that they aren't being passed through the shaders, however the shaders are functioning as I'm getting no errors (to my knowledge, I can't be sure). The engine itself is going to be open source and free anyways, so I don't mind posting the source here. Coded in Java, using OpenGL (from LWJGL), and in Eclipse (Neon) format. Warning: When first running the engine, it will spit out an error saying it couldn't find a config file, this will then generate a new folder in your %appdata% directory labeled 'Fusion Engine' with a Core.cfg file. This file can be opened in any old text editor, so if you aren't comfortable with that just change it in the source at: "src/utility/ConfigManager.java" before running. Just ask if you need more info, please I've been trying to fix this for a month now. Fusion Engine V2.zip
  3. FireFlood

    Lobby, Connection

    Language: Java Greetings. I'm developing a multiplayer / singleplayer game. I've already wrote all the game logic and byte protocol for in-game communication. 1. Lobby What I need is an implementation of a lobby which supports these basic functions: create room join room switch room host change room settings (module id (see below), max players, map, etc) send private / public message switch room / player state start game session I've made a very raw, unstable version of this using Netty framework over TCP protocol, however I am not against open-source ready solutions, but I could't find any, besides Nadron. 2. Client connection. Though my logic code basic is very simple, a large chunk of it described in concrete "Module" which is a pack of scripts, json files, maps, and, additionally, contains all the textures, sounds and other game materials. What I need is when a client wants to join server, all the server modules will be somehow sent to the client and only after that they join. Basically I need the same behaviour as how it happens, for example, in Garry's Mod when player joins the server. I thought of 2 approaches: 1. A single download-upload server db which somehow synchronize with game server and notify when client finishes downloading. (Example: Steam Workshop) 2. Since game server handles its own module db it will also send the information to all incoming clients. (Example: pretty sure all private or cracked servers) Am I right? Sure, I could use raw Netty, but it will be a huge pain in the ass to implement a stable lobby logic, file serializing / transfer and sync all of this since I have no real experience in net programming. What Java technologies / frameworks would you recommend for this case? Or should I stick to Netty?
  4. Hello, I am trying to make a GeometryUtil class that has methods to draw point,line ,polygon etc. I am trying to make a method to draw circle. There are many ways to draw a circle. I have found two ways, The one way: public static void drawBresenhamCircle(PolygonSpriteBatch batch, int centerX, int centerY, int radius, ColorRGBA color) { int x = 0, y = radius; int d = 3 - 2 * radius; while (y >= x) { drawCirclePoints(batch, centerX, centerY, x, y, color); if (d <= 0) { d = d + 4 * x + 6; } else { y--; d = d + 4 * (x - y) + 10; } x++; //drawCirclePoints(batch,centerX,centerY,x,y,color); } } private static void drawCirclePoints(PolygonSpriteBatch batch, int centerX, int centerY, int x, int y, ColorRGBA color) { drawPoint(batch, centerX + x, centerY + y, color); drawPoint(batch, centerX - x, centerY + y, color); drawPoint(batch, centerX + x, centerY - y, color); drawPoint(batch, centerX - x, centerY - y, color); drawPoint(batch, centerX + y, centerY + x, color); drawPoint(batch, centerX - y, centerY + x, color); drawPoint(batch, centerX + y, centerY - x, color); drawPoint(batch, centerX - y, centerY - x, color); } The other way: public static void drawCircle(PolygonSpriteBatch target, Vector2 center, float radius, int lineWidth, int segments, int tintColorR, int tintColorG, int tintColorB, int tintColorA) { Vector2[] vertices = new Vector2[segments]; double increment = Math.PI * 2.0 / segments; double theta = 0.0; for (int i = 0; i < segments; i++) { vertices[i] = new Vector2((float) Math.cos(theta) * radius + center.x, (float) Math.sin(theta) * radius + center.y); theta += increment; } drawPolygon(target, vertices, lineWidth, segments, tintColorR, tintColorG, tintColorB, tintColorA); } In the render loop: polygonSpriteBatch.begin(); Bitmap.drawBresenhamCircle(polygonSpriteBatch,500,300,200,ColorRGBA.Blue); Bitmap.drawCircle(polygonSpriteBatch,new Vector2(500,300),200,5,50,255,0,0,255); polygonSpriteBatch.end(); I am trying to choose one of them. So I thought that I should go with the one that does not involve heavy calculations and is efficient and faster. It is said that the use of floating point numbers , trigonometric operations etc. slows down things a bit. What do you think would be the best method to use? When I compared the code by observing the time taken by the flow from start of the method to the end, it shows that the second one is faster. (I think I am doing something wrong here ). Please help! Thank you.
  5. I'm using the OPENGL with eclipse+JOGL.My goal is to create movement of the camera and the player.I create main class, which create some box in 3D and hold an object of PlayerAxis.I create PlayerAxis class which hold the axis of the player.If we want to move the camera, then in the main class I call to the func "cameraMove"(from PlayerAxis) and it update the player axis.That's work good.The problem start if I move the camera on 2 axis, for example if I move with the camera right(that's on the y axis)and then down(on the x axis) -in some point the move front is not to the front anymore..In order to move to the front, I doplayer.playerMoving(0, 0, 1);And I learn that in order to keep the front move, I need to convert (0, 0, 1) to the player axis, and then add this.I think I dont do the convert right.. I will be glad for help!Here is part of my PlayerAxis class: //player coordinate float x[] = new float[3]; float y[] = new float[3]; float z[] = new float[3]; public PlayerAxis(float move_step, float angle_move) { x[0] = 1; y[1] = 1; z[2] = -1; step = move_step; angle = angle_move; setTransMatrix(); } public void cameraMoving(float angle_step, String axis) { float[] new_x = x; float[] new_y = y; float[] new_z = z; float alfa = angle_step * angle; switch(axis) { case "x": new_z = addVectors(multScalar(z, COS(alfa)), multScalar(y, SIN(alfa))); new_y = subVectors(multScalar(y, COS(alfa)), multScalar(z, SIN(alfa))); break; case "y": new_x = addVectors(multScalar(x, COS(alfa)), multScalar(z, SIN(alfa))); new_z = subVectors(multScalar(z, COS(alfa)), multScalar(x, SIN(alfa))); break; case "z": new_x = addVectors(multScalar(x, COS(alfa)), multScalar(y, SIN(alfa))); new_y = subVectors(multScalar(y, COS(alfa)), multScalar(x, SIN(alfa))); } x = new_x; y = new_y; z = new_z; normalization(); } public void playerMoving(float x_move, float y_move, float z_move) { float[] move = new float[3]; move[0] = x_move; move[1] = y_move; move[2] = z_move; setTransMatrix(); float[] trans_move = transVector(move); position[0] = position[0] + step*trans_move[0]; position[1] = position[1] + step*trans_move[1]; position[2] = position[2] + step*trans_move[2]; } public void setTransMatrix() { for (int i = 0; i < 3; i++) { coordiTrans[0][i] = x[i]; coordiTrans[1][i] = y[i]; coordiTrans[2][i] = z[i]; } } public float[] transVector(float[] v) { return multiplyMatrixInVector(coordiTrans, v); } and in the main class i have this: public void keyPressed(KeyEvent e) { if (e.getKeyCode()== KeyEvent.VK_ESCAPE) { System.exit(0); //player move } else if (e.getKeyCode()== KeyEvent.VK_W) { //front //moveAmount[2] += -0.1f; player.playerMoving(0, 0, 1); } else if (e.getKeyCode()== KeyEvent.VK_S) { //back //moveAmount[2] += 0.1f; player.playerMoving(0, 0, -1); } else if (e.getKeyCode()== KeyEvent.VK_A) { //left //moveAmount[0] += -0.1f; player.playerMoving(-1, 0, 0); } else if (e.getKeyCode()== KeyEvent.VK_D) { //right //moveAmount[0] += 0.1f; player.playerMoving(1, 0, 0); } else if (e.getKeyCode()== KeyEvent.VK_E) { //moveAmount[0] += 0.1f; player.playerMoving(0, 1, 0); } else if (e.getKeyCode()== KeyEvent.VK_Q) { //moveAmount[0] += 0.1f; player.playerMoving(0, -1, 0); //camera move } else if (e.getKeyCode()== KeyEvent.VK_I) { //up player.cameraMoving(1, "x"); } else if (e.getKeyCode()== KeyEvent.VK_K) { //down player.cameraMoving(-1, "x"); } else if (e.getKeyCode()== KeyEvent.VK_L) { //right player.cameraMoving(-1, "y"); } else if (e.getKeyCode()== KeyEvent.VK_J) { //left player.cameraMoving(1, "y"); } else if (e.getKeyCode()== KeyEvent.VK_O) { //right round player.cameraMoving(-1, "z"); } else if (e.getKeyCode()== KeyEvent.VK_U) { //left round player.cameraMoving(1, "z"); } } finallt found it.... i confused with the transformation matrix row and col. thanks anyway!
  6. This week Hello everyone! This week, as always, I fixed few bugs, did few tweaks and implemented small features. Here's a list of things I've done this week: Tweaked enemy prices and levels. Added object picking Added sounds and music Tweaked audio gains for different sounds and music Added capability of selling towers Added new cursor Implemented support for multiple enemy waves Added new enemy: Tank Added new turret type: Rocket turret Screenshots: Important decision Yesterday I came to important realization while making my game. I realized that I need to build a fully working prototype of the game, figure out all the mechanics, implement all the tower and enemy types first and only then continue doing the minor things and polishing things up. I also realized that I should spend less time on music and 3D models. All these things will be done, but not now. I need to make my game fun first, and only then worry about all the assets. I don't want to repeat same mistake which I did with my previous games where I spent too much time on graphics, sounds, performance optimizations and too little time for actual gameplay mechanics. Problems There's one problem which I currently face, and it has to do with the "Tesla Coil" tower. As of now it slows down the enemies in its range, but there's a problem with that. The problem arises when you put the tower at the very end of the maze. When you do that, it not only slows down the enemies in its range, but it also slows down any enemies which came before them. This is because of the obstacle avoidance which makes it so that the enemies couldn't go through each other like some sort of ghosts. The only solution which I can think of right now is to remove this type of tower and replace it with something else. Next week This coming week I'll start thinking of and implementing all the different tower and enemy types. I might do some very basic 3D models to use as placeholders as well. That's all for now, thanks for reading Twitter: https://twitter.com/extrabitgamesFacebook: https://www.facebook.com/extrabitgamesWebsite: http://extrabitgames.com
  7. Hello again, everyone! Today is going to be a very short blog entry because all I wanted to show you is the new soundtracks which I created. As of now I only have 2 soundtracks, but I plan on making total of 12, or at least 10. The genre I choose is psychedelic trance. The main reason for it is because it's fast paced and I think it would suit my game pretty well. I also added shooting and exploding sounds which make the game just a bit more interesting. You can have a listen of the soundtracks here: That's all for today, thanks for reading! Twitter: https://twitter.com/extrabitgames Facebook: https://www.facebook.com/extrabitgames Website: http://extrabitgames.com
  8. Subscribe to our subreddit to get all the updates from the team! Recently I've been tackling with more organic low poly terrains. The default way of creating indices for a 3D geometry is the following (credits) : A way to create simple differences that makes the geometry slightly more complicated and thus more organic is to vertically swap the indices of each adjacent quad. In other words, each adjacent quad to a centered quad is its vertical mirror. Finally, by not sharing the vertices and hence by creating two triangles per quad, this is the result with a coherent noise generator (joise) : It is called flat shading.
  9. Good day, everyone! This week I've been working on various small fixes, improvements and features. Here's an incomplete list of all the things I've done: As you can see there are quite a few commits related to performance improvements such as added frustum culling, improved memory usage, pathfinding improvements and so on. The one main thing that's missing from this list is the addition of the new tower type which for now I just call "the slower" which as the name suggests, slows down the enemies. If any of you have played the original Red Alert you might notice that for this particular tower I took inspiration from the so called Tesla Coil. The only difference is that instead of electrocuting it's enemies, it just slows them down. Here's how it looks in Blender: And in game: Also, for the above image you can see how the UI looks. It's still very primitive and will be changed later on, but for now it does the trick. It lets to select a tower and tell the game when you are ready for the level to begin. Another thing which I've been working on was music. The funny thing is the genre which I chose. It's psytrance I thought that the fast tempo and monotonic bassline would be suitable for this type of game. After all, it is KIND of an action game. And the way I see it, when it's finished, there will be lots of explosions going on. Anyways, as mentioned in the list above, I also implemented placeholder main and options menus along with splash screen. This is how the menus look now (keep in mind they will be changed later on): Yes, very simple, I know. But they get the job done and it's still very early in development. One more thing which I added is money. You can now purchase towers and you will get money for each killed enemy. For now there's not functionality for selling the towers but it will be added soon. So that's all for this week. And for the next week, I think I will be doing 3D modelling and will be implementing new tower types along with other minor features. Twitter: https://twitter.com/extrabitgames Facebook: https://www.facebook.com/extrabitgames Website: http://extrabitgames.com
  10. thecheeselover

    Marching cubes

    Subscribe to our subreddit to get all the updates from the team! I have had difficulties recently with the Marching Cubes algorithm, mainly because the principal source of information on the subject was kinda vague and incomplete to me. I need a lot of precision to understand something complicated Anyhow, after a lot of struggles, I have been able to code in Java a less hardcoded program than the given source because who doesn't like the cuteness of Java compared to the mean looking C++? Oh and by hardcoding, I mean something like this : cubeindex = 0; if (grid.val[0] < isolevel) cubeindex |= 1; if (grid.val[1] < isolevel) cubeindex |= 2; if (grid.val[2] < isolevel) cubeindex |= 4; if (grid.val[3] < isolevel) cubeindex |= 8; if (grid.val[4] < isolevel) cubeindex |= 16; if (grid.val[5] < isolevel) cubeindex |= 32; if (grid.val[6] < isolevel) cubeindex |= 64; if (grid.val[7] < isolevel) cubeindex |= 128; By no mean I am saying that my code is better or more performant. It's actually ugly. However, I absolutely loathe hardcoding. Here's the result with a scalar field generated using the coherent noise library joise :
  11. thecheeselover

    Zone division

    Subscribe to our subreddit to get all the updates from the team! A friend and I are making a rogue-lite retro procedural game. As in many procedural rogue-lite games, it will have rooms to complete but also the notion of zones. The difference between a zone and a room is that a zone is open air whilst a room is not. Rooms are connected mainly by corridors while zones are mostly naturally connected / separated by rivers and mountains. Because we want levels with zones to be generated, we need to tame the beast that is procedural generation. How can we generate each zone itself and also clearly divide them? Until now, I had only been using the Java noise library called Joise, which is the Java community port of JTippetts' Accidental Noise Library. I needed the zone data to be generated with basis function modules, i.e. Perlin noise, but in contrast I needed a more structured approach for the zone division. Joise library does have a cell noise module that is a Worley noise. It looks like this depending on its 4 parameters (1, 0, 0, 0) : Using math modules, I was able to morph that noise into something that looks like a Voronoi diagram. Here's what a Voronoi diagram should look like (never mind the colors, the important parts are the cell edges and the cell centers) : A more aesthetic version : The Worley noise that I had morphed into a Voronoi-like diagram did not include the cell centers, did not include metadata about the edges and was not enough deterministic in a sense that sometimes, the edges would around 60 pixels large. I then searched for a Java Voronoi library and found this one called Voronoi-Java. With this, I was able to generate simple Voronoi diagrams : Relaxed : 1 iteration Relaxed : 2 iterations The relaxation concept is actually the Lloyd's algorithm fortunately included within the library. Now how can I make that diagram respect my level generation mechanics? Well, if we can limit an approximated number of cells within a certain resolution, that would be a good start. The biggest problem here, is that the relaxation reduces the number of cells within a restricted resolution (contrary to the global resolution) and so we need to keep that in mind. To do that, I define a constant for the total number of sites / cells. Here's my code : private Voronoi createVoronoiDiagram(int resolution) { Random random = new Random(); Stream<Point> gen = Stream.generate(() -> new Point(random.nextDouble() * resolution, random.nextDouble() * resolution)); return new Voronoi(gen.limit(VORONOI_SITE_COUNT).collect(Collectors.toList())).relax().relax().relax(); } A brief pseudo-code of the algorithm would be the following : Create the Voronoi diagram Find the centermost zone Selects X number of zones while there are zones that respect the selection criteria Draw the border map Draw the smoothed border map The selection criteria is applied for each edge that is connected only to one selected zone. Here's the selection criteria : Is connected to a closed zone, i.e. that all its edges form a polygon Does have two vertices Is inclusively in the resolution's boundaries Here's the result of a drawn border map! In this graph, I have a restricted number of cells that follow multiple criteria and I know each edge and each cell center point. To draw the smoothed border map, the following actions must be taken : emit colors from already drawn pixels and then apply a gaussian blur. Personally, I use the JH Labs Java Image Filters library for the gaussian blur. With color emission only : With color emission and a gaussian blur : You may ask yourself why have we created a smoothed border map? There's a simple reason for this, which is that we want the borders to be gradual instead of abrupt. Let's say we want rivers or streams between zones. This gradual border will allow us to progressively increase the depth of the river and making it look more natural in contrast with the adjacent zones. All that's left is to flood each selected cell and apply that to a zone map.
  12. thecheeselover

    Unit Vision

    Subscribe to our subreddit to get all the updates from the team! First off, here's a video that shows the unit vision in action : So, what is the unit vision? It's a simple mechanism that notifies a unit when another unit enters its vision field. It also takes into account if the vision is blocked by entities. This is how it is implemented step by step : A cone ghost control is attached to the unit's head All units intersecting with the cone's AABB fire events (AABB because of how Bullet Physics work) Cast a ray towards the visible unit and then adjust the angle so that it fits in the cone If the ray cast touches the supposedly visible unit, then it is truly visible Using the debug view of Bullet Physics in the jMonkey Engine 3.1, we're able to see what the vision cone actually looks like. And when inside the cone we can't see it because of culling. However, we can see the enemy's arm moving, which is a test I did for when a unit see another unit. Behind a box, the enemy does not move its arm because he can't see me. But when I leave my hiding spot, he can see me again.
  13. 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: 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: 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/extrabitgamesFacebook: https://www.facebook.com/extrabitgamesWebsite: http://extrabitgames.com My website: http://extrabitgames.com
  14. What have I done this week This week I have fixed few bugs and finally implemented a fully working obstacle avoidance system which makes my pathfinding and collision/obstacle avoidance system done. Some minor things which I did include: Fixed bug where text rendering causes lighting issues Added calculation of game entity's axis-aligned bounding box from data contained in .obj file Added AABB to AABB collision detection and response Added Ray to AABB intersection detection Made the map size resizable My own solution to obstacle avoidance problem I had really hard time finding information about an easy way to do obstacle avoidance in the way I wanted it to be. So instead I worked few days and came up with my own solution which works pretty well. I think I kind of reinvented a wheel and someone might have a better approach to this problem than I do. But anyways, it's already done and it works the way I wanted it to, which is all I care about now. What I wanted from my obstacle avoidance/collision system For the obstacle avoidance system I wanted it to do few things: Stop the vehicle if it gets too close to other vehicle If vehicles are about to collide (traveling towards each other at the angle less than the threshold angle) then make them steer away from each other Don't ever let two vehicles overlap I tried and I failed Before I explain how it works, I will say things which I tried and which didn't work that well. First thing I tried was to create a separate AABB in the front of the enemy's car and check if it collides with any other car. If it does, stop the vehicle. I thought this would make it so that the vehicles wouldn't get too close to each other and hence wouldn't overlap. Well, that didn't work. Because when both vehicles collide to each other, they will both stop and will get stuck. To fix this, I added an if statement which checks whether the vehicles collide at each other if so, make it so that only one of two vehicles would stop and other would continue driving. But this made them overlap some of the times, which I didn't want. So after thinking for a while, I decided I should add AABB collision response, so that when cars hit each other they don't overlap, but get pushed back. So I did that and now it works pretty good, BUT if the vehicles are travelling towards each other there's no way of knowing which way to turn to avoid the collision. So I decided to scrap this AABB in front of the vehicle approach and try casting rays. Approach which worked My last and final try was to use rays instead of AABB to check for collisions with other entities. This time I say entities because I also want to check if the ray intersects the towers as well, this way we will know which way the vehicle can turn to avoid collisions. So the way I do it is pretty simple. The vehicle casts number of rays from its center towards the front of the car which check for intersection between towers' and enemies' bounding boxes. Then I have a function which does some magic and calculates (from the ray intersection information) which way the vehicle should steer. This steering is only done if two vehicles are facing each other and moving towards. If they are not moving towards, I check if the ray distance is smaller than the threshold value and if it is I just stop the vehicle. There are other few tiny hacks and tricks which I did to polish the system. But this is mainly how it works. Next week I still haven't decided what I am going to do this coming week. But I think I will add different tower types, add GUI and make it so that enemies will spawn inside a building or in a hidden area from where they will come to the game's map. You can see the state of the game here: Twitter: https://twitter.com/extrabitgamesFacebook: https://www.facebook.com/extrabitgamesWebsite: http://extrabitgames.com
  15. I'm still working on large RPG top down game that has very large maps 500 x500 32 x 32 px tiles and there 5 of these "land maps" each with three large buildings of a "200*200" tiled map some with more than one map for each floor. and shops taverns/ blacksmiths/ stables / houses with 20 x 20 or so tile maps. Since you can have / control more than one unit to optimize the game I was thinking each map ( land map, shop, tavern, budiling ect.) should have it's own game loop. There would be a button created for each map you have units on to switch to that map and when you switch them one loop is paused and the other one is activated? Is this a good idea?
  16. bojanzarnoski@gmx.de

    Java 2D Platforming: Java or C#

    Hello, I want to get into coding again by programming a 2D platformer to get started, but i don't know if i should use Java or C# with the unity engine. I am pretty fit with Java, but with c# i have to start from scratch. What do you recommend and why?
  17. Jumpaï is a game about creating platformer levels and playing them online with everyone. Will you become the most popular level maker or will you be a speedrunner holding world records on everyone's levels? More into casual play? No problem! You can happily play through the giant level database or chill at people's hub. Meet new people, make new friends, learn to master the game by asking pros or ask for people's favorite tricks on level making. Download here: https://jumpai.itch.io/jumpai Discord: https://discord.gg/dwRTNCG Trailer: (The following screenshots are older but still a bit representative) Unlike other games of its genre, Jumpaï is about playing levels with everyone in real time. You have the fun to see how other people are playing and get to realize you are not the only one failing that jump! The game is currently into development and still have lots to do. I am looking for people willing to help how they can. Developer? Graphist? Play tester? Sound designer? Game designer? I'm welcoming any talent. The project is so big I have a lot of work to do in all areas. Server backend, UI/UX, Game networking, Gameplay and even the website some day. As you can see from the default buttons, the game has been made with LibGDX. This project is a perfect opportunity for you to get better in various fields as well as showing off your skills. If you plan to take an important role into the development of the game, we will discuss how you will get paid once the game generates money. Note that I'm not working on the game full-time. I'm studying full-time and working on it is a hobby. The project has started in november 2016 and experiences heavy progress.So, are you interested? If so join me on my discord https://discord.gg/dwRTNCG and I'll answer all your questions.Additionnal screenshots:
  18. Hello! I’m a programmer from Denmark currently putting together a team of amateurs to help develop my current project. It is a war simulation game, HOWEVER, it is not like anything else currently on the market. If you would like to hear more about my project, message me on discord, or if you would like to join, do the same. You do not need to be a professional, as this is solely a learning experience for everyone involved. The positions I am seeking go as follows: - 3D Modeler - 2D Artist - Musical Composer - Game Designer - Level Designer Discord: Coa#0698
  19. Not long ago, I create a nice OBJ loader that loads 3D Studio Max files. Only problem is, is that although it works and works great, I wasn't using Vertex Buffers. Now that I applied Vertex Buffers, it seems to only use the first color of the texture and spread it all across the poiygon. I examined my code over and over again, and the Vertex Buffer code is correct. But when I comment out all of my vertex buffer code, it works as intended. I practically given up on fixing it on my own, so hopefully you guys will be able to figure out what is wrong. public static final int BYTES_PER_FLOAT = 4; public static final int POSITION_COMPONENT_COUNT_3D = 4; public static final int COLOR_COMPONENT_COUNT = 4; public static final int TEXTURE_COORDINATES_COMPONENT_COUNT = 2; public static final int NORMAL_COMPONENT_COUNT = 3; public static final int POSITION_COMPONENT_STRIDE_2D = POSITION_COMPONENT_COUNT_2D * BYTES_PER_FLOAT; public static final int POSITION_COMPONENT_STRIDE_3D = POSITION_COMPONENT_COUNT_3D * BYTES_PER_FLOAT; public static final int COLOR_COMPONENT_STRIDE = COLOR_COMPONENT_COUNT * BYTES_PER_FLOAT; public static final int TEXTURE_COORDINATE_COMPONENT_STRIDE = TEXTURE_COORDINATES_COMPONENT_COUNT * BYTES_PER_FLOAT; public static final int NORMAL_COMPONENT_STRIDE = NORMAL_COMPONENT_COUNT * BYTES_PER_FLOAT; int loadFile() { ArrayList<Vertex3D> tempVertexArrayList = new ArrayList<Vertex3D>(); ArrayList<TextureCoord2D> tempTextureCoordArrayList = new ArrayList<TextureCoord2D>(); ArrayList<Vector3D> tempNormalArrayList = new ArrayList<Vector3D>(); ArrayList<Face3D> tempFaceArrayList = new ArrayList<Face3D>(); StringBuilder body = new StringBuilder(); try { InputStream inputStream = context.getResources().openRawResource(resourceID); InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String nextLine; String subString; String[] stringArray; String[] stringArray2; int[] indexNumberList = new int[3]; int[] textureCoordNumberList = new int[3]; int[] normalNumberList = new int[3]; int i = 0; int j = 0; int k = 0; try { while ((nextLine = bufferedReader.readLine()) != null) { if (nextLine.startsWith("v ")) { subString = nextLine.substring(1).trim(); stringArray = subString.split(" "); try { tempVertexArrayList.add(new Vertex3D(Float.parseFloat(stringArray[0]), Float.parseFloat(stringArray[1]), Float.parseFloat(stringArray[2]), 1f)); } catch(NumberFormatException e){ Log.d(TAG, "Error: Invalid number format in loading vertex list"); return 0; } String x = String.valueOf(tempVertexArrayList.get(i).x); String y = String.valueOf(tempVertexArrayList.get(i).y); String z = String.valueOf(tempVertexArrayList.get(i).z); //Log.d(TAG, "vertex " + String.valueOf(i) + ": " + x + ", " + y + ", " + z); i++; } if (nextLine.startsWith("vn ")) { subString = nextLine.substring(2).trim(); stringArray = subString.split(" "); try { if(reverseNormals){ tempNormalArrayList.add(new Vector3D(-Float.parseFloat(stringArray[0]), -Float.parseFloat(stringArray[1]), -Float.parseFloat(stringArray[2]))); } else{ tempNormalArrayList.add(new Vector3D(Float.parseFloat(stringArray[0]), Float.parseFloat(stringArray[1]), Float.parseFloat(stringArray[2]))); } } catch(NumberFormatException e){ Log.d(TAG, "Error: Invalid number format in loading normal list"); return 0; } String nx = String.valueOf(tempNormalArrayList.get(j).x); String ny = String.valueOf(tempNormalArrayList.get(j).y); String nz = String.valueOf(tempNormalArrayList.get(j).z); //Log.d(TAG, "normal " + String.valueOf(j) + ": " + nx + ", " + ny + ", " + nz); j++; } if (nextLine.startsWith("vt ")) { subString = nextLine.substring(2).trim(); stringArray = subString.split(" "); try { tempTextureCoordArrayList.add(new TextureCoord2D(Float.parseFloat(stringArray[0]), Float.parseFloat(stringArray[1]))); } catch(NumberFormatException e){ Log.d(TAG, "Error: Invalid number format in loading texture coordinate list"); return 0; } String tu = String.valueOf(tempTextureCoordArrayList.get(k).tu); String tv = String.valueOf(tempTextureCoordArrayList.get(k).tv); //Log.d(TAG, "texture coord " + String.valueOf(k) + ": " + tu + ", " + tv); k++; } if (nextLine.startsWith("f ")) { subString = nextLine.substring(1).trim(); stringArray = subString.split(" "); for (int index = 0; index <= 2; index++) { stringArray2 = stringArray[index].split("/"); try { indexNumberList[index] = Integer.parseInt(stringArray2[0]) - 1; if(indexNumberList[index] < 0){ Log.d(TAG, "Error: indexNumberList[] is less than zero"); return 0; } } catch(NumberFormatException e){ Log.d(TAG, "Error: Invalid number format in loading indexNumberList[]"); return 0; } try{ textureCoordNumberList[index] = Integer.parseInt(stringArray2[1]) - 1; if(textureCoordNumberList[index] < 0){ Log.d(TAG, "Error: textureCoordNumberList[] is less than zero"); return 0; } } catch(NumberFormatException e){ Log.d(TAG, "Error: Invalid number format in loading textureCoordNumberList[]"); return 0; } try{ normalNumberList[index] = Integer.parseInt(stringArray2[2]) - 1; if(normalNumberList[index] < 0){ Log.d(TAG, "Error: normalNumberList[] is less than zero"); return 0; } } catch(NumberFormatException e){ Log.d(TAG, "Error: Invalid number format in loading normalNumberList[]"); return 0; } } tempFaceArrayList.add(new Face3D(indexNumberList[0], textureCoordNumberList[0], normalNumberList[0], indexNumberList[1], textureCoordNumberList[1], normalNumberList[1], indexNumberList[2], textureCoordNumberList[2], normalNumberList[2])); } body.append(nextLine); body.append('\n'); } //Now that everything has successfully loaded, you can now populate the public variables. if(tempVertexArrayList != null && tempVertexArrayList.size() != 0) vertexArrayList.addAll(tempVertexArrayList); if(tempTextureCoordArrayList != null && tempTextureCoordArrayList.size() != 0) textureCoordArrayList.addAll(tempTextureCoordArrayList); if(tempNormalArrayList != null && tempNormalArrayList.size() != 0) normalArrayList.addAll(tempNormalArrayList); if(tempFaceArrayList != null && tempFaceArrayList.size() != 0) faceArrayList.addAll(tempFaceArrayList); vertexList = new float[faceArrayList.size() * POSITION_COMPONENT_COUNT_3D * NUMBER_OF_SIDES_PER_FACE]; indexList = new short[faceArrayList.size() * NUMBER_OF_SIDES_PER_FACE]; colorList = new float[faceArrayList.size() * COLOR_COMPONENT_COUNT * NUMBER_OF_SIDES_PER_FACE]; textureCoordList = new float[faceArrayList.size() * TEXTURE_COORDINATES_COMPONENT_COUNT * NUMBER_OF_SIDES_PER_FACE]; normalList = new float[faceArrayList.size() * NORMAL_COMPONENT_COUNT * NUMBER_OF_SIDES_PER_FACE]; int nextFace = 0; int step = POSITION_COMPONENT_COUNT_3D * NUMBER_OF_SIDES_PER_FACE; for (int currentVertex = 0; currentVertex < vertexList.length; currentVertex += step){ vertexList[currentVertex + 0] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(0)).x; vertexList[currentVertex + 1] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(0)).y; vertexList[currentVertex + 2] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(0)).z; vertexList[currentVertex + 3] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(0)).w; vertexList[currentVertex + 4] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(1)).x; vertexList[currentVertex + 5] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(1)).y; vertexList[currentVertex + 6] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(1)).z; vertexList[currentVertex + 7] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(1)).w; vertexList[currentVertex + 8] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(2)).x; vertexList[currentVertex + 9] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(2)).y; vertexList[currentVertex + 10] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(2)).z; vertexList[currentVertex + 11] = vertexArrayList.get(faceArrayList.get(nextFace).indexNumberList.get(2)).w; nextFace++; } numberOfVertices = vertexList.length / POSITION_COMPONENT_COUNT_3D; nextFace = 0; for (int currentIndex = 0; currentIndex < indexList.length; currentIndex += NUMBER_OF_SIDES_PER_FACE){ indexList[currentIndex + 0] = faceArrayList.get(nextFace).indexNumberList.get(0).shortValue(); indexList[currentIndex + 1] = faceArrayList.get(nextFace).indexNumberList.get(1).shortValue(); indexList[currentIndex + 2] = faceArrayList.get(nextFace).indexNumberList.get(2).shortValue(); } step = COLOR_COMPONENT_COUNT * NUMBER_OF_SIDES_PER_FACE; for (int currentVertex = 0; currentVertex < colorList.length; currentVertex += step){ colorList[currentVertex + 0] = red; colorList[currentVertex + 1] = green; colorList[currentVertex + 2] = blue; colorList[currentVertex + 3] = alpha; colorList[currentVertex + 4] = red; colorList[currentVertex + 5] = green; colorList[currentVertex + 6] = blue; colorList[currentVertex + 7] = alpha; colorList[currentVertex + 8] = red; colorList[currentVertex + 9] = green; colorList[currentVertex + 10] = blue; colorList[currentVertex + 11] = alpha; } nextFace = 0; step = TEXTURE_COORDINATES_COMPONENT_COUNT * NUMBER_OF_SIDES_PER_FACE; for (int currentVertex = 0; currentVertex < textureCoordList.length; currentVertex += step){ textureCoordList[currentVertex + 0] = textureCoordArrayList.get(faceArrayList.get(nextFace).textureCoordNumberList.get(0)).tu * mult; textureCoordList[currentVertex + 1] = textureCoordArrayList.get(faceArrayList.get(nextFace).textureCoordNumberList.get(0)).tv * mult; textureCoordList[currentVertex + 2] = textureCoordArrayList.get(faceArrayList.get(nextFace).textureCoordNumberList.get(1)).tu * mult; textureCoordList[currentVertex + 3] = textureCoordArrayList.get(faceArrayList.get(nextFace).textureCoordNumberList.get(1)).tv * mult; textureCoordList[currentVertex + 4] = textureCoordArrayList.get(faceArrayList.get(nextFace).textureCoordNumberList.get(2)).tu * mult; textureCoordList[currentVertex + 5] = textureCoordArrayList.get(faceArrayList.get(nextFace).textureCoordNumberList.get(2)).tv * mult; nextFace++; } nextFace = 0; step = NORMAL_COMPONENT_COUNT * NUMBER_OF_SIDES_PER_FACE; for (int currentVertex = 0; currentVertex < normalList.length; currentVertex += step){ normalList[currentVertex + 0] = normalArrayList.get(faceArrayList.get(nextFace).normalNumberList.get(0)).x; normalList[currentVertex + 1] = normalArrayList.get(faceArrayList.get(nextFace).normalNumberList.get(0)).y; normalList[currentVertex + 2] = normalArrayList.get(faceArrayList.get(nextFace).normalNumberList.get(0)).z; normalList[currentVertex + 3] = normalArrayList.get(faceArrayList.get(nextFace).normalNumberList.get(1)).x; normalList[currentVertex + 4] = normalArrayList.get(faceArrayList.get(nextFace).normalNumberList.get(1)).y; normalList[currentVertex + 5] = normalArrayList.get(faceArrayList.get(nextFace).normalNumberList.get(1)).z; normalList[currentVertex + 6] = normalArrayList.get(faceArrayList.get(nextFace).normalNumberList.get(2)).x; normalList[currentVertex + 7] = normalArrayList.get(faceArrayList.get(nextFace).normalNumberList.get(2)).y; normalList[currentVertex + 8] = normalArrayList.get(faceArrayList.get(nextFace).normalNumberList.get(2)).z; nextFace++; } vertexBuffer = ByteBuffer.allocateDirect(vertexList.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer(); indexBuffer = ByteBuffer.allocateDirect(indexList.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asShortBuffer(); colorBuffer = ByteBuffer.allocateDirect(colorList.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer(); textureCoordBuffer = ByteBuffer.allocateDirect(textureCoordList.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer(); normalBuffer = ByteBuffer.allocateDirect(normalList.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer(); vertexBuffer.put(vertexList).position(0); indexBuffer.put(indexList).position(0); colorBuffer.put(colorList).position(0); textureCoordBuffer.put(textureCoordList).position(0); normalBuffer.put(normalList).position(0); createVertexBuffer(); uMVPMatrixHandle = glGetUniformLocation(program, U_MVPMATRIX); uMVMatrixHandle = glGetUniformLocation(program, U_MVMATRIX); uTextureUnitHandle = glGetUniformLocation(program, U_TEXTURE_UNIT); aPositionHandle = glGetAttribLocation(program, A_POSITION); aColorHandle = glGetAttribLocation(program, A_COLOR); aTextureCoordinateHandle = glGetAttribLocation(program, A_TEXTURE_COORDINATES); aNormalHandle = glGetAttribLocation(program, A_NORMAL); glEnableVertexAttribArray(aPositionHandle); glEnableVertexAttribArray(aColorHandle); glEnableVertexAttribArray(aTextureCoordinateHandle); glEnableVertexAttribArray(aNormalHandle); glActiveTexture(GL_TEXTURE0); glUniform1i(uTextureUnitHandle, 0); } catch(IOException e){ } } catch (Resources.NotFoundException nfe){ throw new RuntimeException("Resource not found: " + resourceID, nfe); } return 1; } public void draw(){ glEnable(GL_DEPTH_TEST); bindData(); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject[0]); glDrawArrays(GL_TRIANGLES, 0, faceArrayList.size() * NUMBER_OF_SIDES_PER_FACE); glBindBuffer(GL_ARRAY_BUFFER, 0); } public void bindData(){ int offset = 0; glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject[0]); glVertexAttribPointer(aPositionHandle, POSITION_COMPONENT_COUNT_3D, GL_FLOAT, false, POSITION_COMPONENT_STRIDE_3D, offset); offset += POSITION_COMPONENT_COUNT_3D; glVertexAttribPointer(aColorHandle, COLOR_COMPONENT_COUNT, GL_FLOAT, false, COLOR_COMPONENT_STRIDE, numberOfVertices * offset * BYTES_PER_FLOAT); offset += COLOR_COMPONENT_COUNT; glVertexAttribPointer(aTextureCoordinateHandle, TEXTURE_COORDINATES_COMPONENT_COUNT, GL_FLOAT, false, TEXTURE_COORDINATE_COMPONENT_STRIDE, numberOfVertices * offset * BYTES_PER_FLOAT); offset += TEXTURE_COORDINATES_COMPONENT_COUNT; glVertexAttribPointer(aNormalHandle, NORMAL_COMPONENT_COUNT, GL_FLOAT, false, NORMAL_COMPONENT_STRIDE, numberOfVertices * offset * BYTES_PER_FLOAT); glBindBuffer(GL_ARRAY_BUFFER, 0); ///////////////////////////////////////////////////// /* vertexBuffer.position(0); glVertexAttribPointer(aPositionHandle, POSITION_COMPONENT_COUNT_3D, GL_FLOAT, false, POSITION_COMPONENT_STRIDE_3D, vertexBuffer); colorBuffer.position(0); glVertexAttribPointer(aColorHandle, COLOR_COMPONENT_COUNT, GL_FLOAT, false, COLOR_COMPONENT_STRIDE, colorBuffer); textureCoordBuffer.position(0); glVertexAttribPointer(aTextureCoordinateHandle, TEXTURE_COORDINATES_COMPONENT_COUNT, GL_FLOAT, false, TEXTURE_COORDINATE_COMPONENT_STRIDE, textureCoordBuffer); normalBuffer.position(0); glVertexAttribPointer(aNormalHandle, NORMAL_COMPONENT_COUNT, GL_FLOAT, false, NORMAL_COMPONENT_STRIDE, normalBuffer); */ } public void createVertexBuffer(){ glGenBuffers(1, vertexBufferObject, 0); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject[0]); glBufferData(GL_ARRAY_BUFFER,numberOfVertices * (POSITION_COMPONENT_COUNT_3D + COLOR_COMPONENT_COUNT + TEXTURE_COORDINATES_COMPONENT_COUNT + NORMAL_COMPONENT_COUNT) * BYTES_PER_FLOAT, null, GL_STATIC_DRAW); int offset = 0; glBufferSubData(GL_ARRAY_BUFFER, offset, numberOfVertices * POSITION_COMPONENT_COUNT_3D * BYTES_PER_FLOAT, vertexBuffer); offset += POSITION_COMPONENT_COUNT_3D; glBufferSubData(GL_ARRAY_BUFFER, numberOfVertices * offset * BYTES_PER_FLOAT, numberOfVertices * COLOR_COMPONENT_COUNT * BYTES_PER_FLOAT, colorBuffer); offset += COLOR_COMPONENT_COUNT; glBufferSubData(GL_ARRAY_BUFFER, numberOfVertices * offset * BYTES_PER_FLOAT, numberOfVertices * TEXTURE_COORDINATES_COMPONENT_COUNT * BYTES_PER_FLOAT, textureCoordBuffer); offset += TEXTURE_COORDINATES_COMPONENT_COUNT; glBufferSubData(GL_ARRAY_BUFFER, numberOfVertices * offset * BYTES_PER_FLOAT, numberOfVertices * NORMAL_COMPONENT_COUNT * BYTES_PER_FLOAT, normalBuffer); glBindBuffer(GL_ARRAY_BUFFER, 0); }
  20. I've been digging around online and can't seem to find any formulas for 3D mesh simplification. I'm not sure where to start but I generally want to know how I could make a function that takes in an array of vertices, indices, and a float/double for the decimation rate. And could I preserve the general shape of the object too? Thanks for the help! P.S. I was hoping to do something with Quadric Error / Quadric Edge Collapse if that's possible.
  21. Steering behaviors are use to maneuver IA agents in a 3D environment. With these behaviors, agents are able to better react to changes in their environment. While the navigation mesh algorithm is ideal for planning a path from one point to another, it can't really deal with dynamic objects such as other agents. This is where steering behaviors can help. What are steering behaviors? Steering behaviors are an amalgam of different behaviors that are used to organically manage the movement of an AI agent. For example, behaviors such as obstacle avoidance, pursuit and group cohesion are all steering behaviors... Steering behavior are usually applied in a 2D plane: it is sufficient, easier to implement and understand. (However, I can think of some use cases that require the behaviors to be in 3D, like in games where the agents fly to move) One of the most important behavior of all steering behaviors is the seeking behavior. We also added the arriving behavior to make the agent's movement a whole lot more organic. Steering behaviors are described in this paper. What is the seeking behavior? The seeking behavior is the idea that an AI agent "seeks" to have a certain velocity (vector). To begin, we'll need to have 2 things: An initial velocity (a vector) A desired velocity (also a vector) First, we need to find the velocity needed for our agent to reach a desired point... This is usually a subtraction of the current position of the agent and the desired position. \(\overrightarrow{d} = (x_{t},y_{t},z_{t}) - (x_{a},y_{a},z_{a})\) Here, a represent our agent and t our target. d is the desired velocity Secondly, we must also find the agent's current velocity, which is usually already available in most game engines. Next, we need to find the vector difference between the desired velocity and the agent's current velocity. it literally gives us a vector that gives the desired velocity when we add it to that agent's current velocity. We will call it "steering velocity". \(\overrightarrow{s} = \overrightarrow{d} - \overrightarrow{c}\) Here, s is our steering velocity, c is the agent's current velocity and d is the desired velocity After that, we truncate our steering velocity to a length called the "steering force". Finally, we simply add the steering velocity to the agent's current velocity . // truncateVectorLocal truncate a vector to a given length Vector3f currentDirection = aiAgentMovementControl.getWalkDirection(); Vector3f wantedDirection = targetPosition.subtract(aiAgent.getWorldTranslation()).normalizeLocal().setY(0).multLocal(maxSpeed); // We steer to our wanted direction Vector3f steeringVector = truncateVectorLocal(wantedDirection.subtract(currentDirection), steeringForce); Vector3f newCurrentDirection = MathExt.truncateVectorLocal(currentDirection.addLocal(MathExt.truncateVectorLocal(wantedDirection.subtract(currentDirection), m_steeringForce).divideLocal(m_mass)), maxSpeed); This computation is done frame by frame: this means that the steering velocity becomes weaker and weaker as the agent's current velocity approaches the desired one, creating a kind of interpolation curve. What is the arriving behavior? The arrival behavior is the idea that an AI agent who "arrives" near his destination will gradually slow down until it gets there. We already have a list of waypoints returned by the navigation mesh algorithm for which the agent must cross to reach its destination. When it has passed the second-to-last point, we then activate the arriving behavior. When the behavior is active, we check the distance between the destination and the current position of the agent and change its maximum speed accordingly. // This is the initial maxSpeed float maxSpeed = unitMovementControl.getMoveSpeed(); // It's the last waypoint float distance = aiAgent.getWorldTranslation().distance(nextWaypoint.getCenter()); float rampedSpeed = aiAgentMovementControl.getMoveSpeed() * (distance / slowingDistanceThreshold); float clippedSpeed = Math.min(rampedSpeed, aiAgentMovementControl.getMoveSpeed()); // This is our new maxSpeed maxSpeed = clippedSpeed; Essentially, we slow down the agent until it gets to its destination. The future? As I'm writing this, we've chosen to split the implementation of the steering behaviors individually to implement only the bare necessities, as we have no empirical evidence that we'll need to implement al of them. Therefore, we only implemented the seeking and arriving behaviors, delaying the rest of the behaviors at an indeterminate time in the future,. So, when (or if) we'll need it, we'll already have a solid and stable foundation from which we can build upon. More links Understanding Steering Behaviors: Seek Steering Behaviors · libgdx/gdx-ai Wiki Understanding Steering Behaviors: Collision Avoidance
  22. I'm programing a game with mario in Java. When I run the code, it does not give an error, but the character does not move. I checked every bit but I could not find the error. I left the codes down. What should I do? Oyun.class OyunEkrani.class
  23. I recently worked on a path-finding algorithm used to move an AI agent into an organically generated dungeon. It's not an easy task but because I've already worked on Team Fortress 2 cards in the past, I already knew navigation meshes (navmesh) and their capabilities. Why Not Waypoints? As described in this paper, waypoint networks were in the past used in video games to save valuable resources. It was an acceptable compromise : level designers already knew where NPCs could and could not go. However, as technology has evolved, computers got more memory that became faster and cheaper. In other words, there was a shift from efficiency to flexibility. In a way, navigation meshes are the evolution of waypoints networks because they fulfill the same need but in a different way. One of the advantages of using a navigation mesh is that an agent can go anywhere in a cell as long as it is convex because it is essentially the definition of convex. It also means that the agent is not limited to a specific waypoint network, so if the destination is out of the waypoint network, it can go directly to it instead of going to the nearest point in the network. A navigation mesh can also be used by many types of agents of different sizes, rather than having many waypoint networks for agents of different sizes. Using a navigation mesh also speeds up graph exploration because, technically, a navigation mesh has fewer nodes than an equivalent waypoint network (that is, a network that has enough points to cover a navigation mesh). The navigation mesh Graph To summarize, a navigation mesh is a mesh that represents where an NPC can walk. A navigation mesh contains convex polygonal nodes (called cells). Each cell can be connected to each other using connections defined by an edge shared between them (or portal edge). In a navigation mesh, each cell can contain information about itself. For example, a cell may be labeled as toxic, and therefore only those units capable of resisting this toxicity can move across it. Personally, because of my experience, I view navigation meshes like the ones found in most Source games. However, all cells in Source's navigation meshes are rectangular. Our implementation is more flexible because the cells can be irregular polygons (as long as they're convex). Navigation Meshes In practice A navigation mesh implementation is actually three algorithms : A graph navigation algorithm A string pulling algorithm And a steering/path-smoothing algorithm In our cases, we used A*, the simple stupid funnel algorithm and a traditional steering algorithm that is still in development. Finding our cells Before doing any graph searches, we need to find 2 things : Our starting cell Our destination cell For example, let's use this navigation mesh : In this navigation meshes, every edge that are shared between 2 cells are also portal edges, which will be used by the string pulling algorithm later on. Also, let's use these points as our starting and destination points: Where our buddy (let's name it Buddy) stands is our staring point, while the flag represents our destination. Because we already have our starting point and our destination point, we just need to check which cell is closest to each point using an octree. Once we know our nearest cells, we must project the starting and destination points onto their respective closest cells. In practice, we do a simple projection of both our starting and destination points onto the normal of their respective cells. Before snapping a projected point, we must first know if the said projected point is outside its cell by finding the difference between the area of the cell and the sum of the areas of the triangles formed by that point and each edge of the cell. If the latter is remarkably larger than the first, the point is outside its cell. The snapping then simply consists of interpolating between the vertices of the edge of the cell closest to the projected point. In terms of code, we do this: Vector3f lineToPoint = pointToProject.subtract(start); Vector3f line = end.subtract(start); Vector3f returnedVector3f = new Vector3f().interpolateLocal(start, end, lineToPoint.dot(line) / line.dot(line)); In our example, the starting and destination cells are C1 and C8 respectively: Graph Search Algorithm A navigation mesh is actually a 2D grid of an unknown or infinite size. In a 3D game, it is common to represent a navigation mesh graph as a graph of flat polygons that aren't orthogonal to each other. There are games that use 3D navigation meshes, like games that use flying AI, but in our case it's a simple grid. For this reason, the use of the A* algorithm is probably the right solution. We chose A* because it's the most generic and flexible algorithm. Technically, we still do not know how our navigation mesh will be used, so going with something more generic can have its benefits... A* works by assigning a cost and a heuristic to a cell. The closer the cell is to our destination, the less expensive it is. The heuristic is calculated similarly but we also take into account the heuristics of the previous cell. This means that the longer a path is, the greater the resulting heuristic will be, and it becomes more likely that this path is not an optimal one. We begin the algorithm by traversing through the connections each of the neighboring cells of the current cell until we arrive at the end cell, doing a sort of exploration / filling. Each cell begins with an infinite heuristic but, as we explore the mesh, it's updated according to the information we learn. In the beginning, our starting cell gets a cost and a heuristic of 0 because the agent is already inside of it. We keep a queue in descending order of cells based on their heuristics. This means that the next cell to use as the current cell is the best candidate for an optimal path. When a cell is being processed, it is removed from that queue in another one that contains the closed cells. While continuing to explore, we also keep a reference of the connection used to move from the current cell to its neighbor. This will be useful later. We do it until we end up in the destination cell. Then, we "reel" up to our starting cell and save each cell we landed on, which gives an optimal path. A* is a very popular algorithm and the pseudocode can easily be found. Even Wikipedia has a pseudocode that is easy to understand. In our example, we find that this is our path: And here are highlighted (in pink) the traversed connections: The String Pulling Algorithm String pulling is the next step in the navigation mesh algorithm. Now that we have a queue of cells that describes an optimal path, we have to find a queue of points that an AI agent can travel to. This is where the sting pulling is needed. String pulling is in fact not linked to characters at all : it is rather a metaphor. Imagine a cross. Let's say that you wrap a silk thread around this cross and you put tension on it. You will find that the string does not follow the inner corner of it, but rather go from corner to corner of each point of the cross. This is precisely what we're doing but with a string that goes from one point to another. There are many different algorithms that lets us to do this. We chose the Simple Stupid Funnel algorithm because it's actually... ...stupidly simple. To put it simply (no puns intended), we create a funnel that checks each time if the next point is in the funnel or not. The funnel is composed of 3 points: a central apex, a left point (called left apex) and a right point (called right apex). At the beginning, the tested point is on the right side, then we alternate to the left and so on until we reach our point of destination. (as if we were walking) When a point is in the funnel, we continue the algorithm with the other side. If the point is outside the funnel, depending on which side the tested point belongs to, we take the apex from the other side of the funnel and add it to a list of final waypoints. The algorithm is working correctly most of the time. However, the algorithm had a bug that add the last point twice if none of the vertices of the last connection before the destination point were added to the list of final waypoints. We just added an if at the moment but we could come back later to optimize it. In our case, the funnel algorithm gives this path: The Steering Algoritm Now that we have a list of waypoints, we can finally just run our character at every point. But if there were walls in our geometry, then Buddy would run right into a corner wall. He won't be able to reach his destination because he isn't small enough to avoid the corner walls. That's the role of the steering algorithm. Our algorithm is still in heavy development, but its main gist is that we check if the next position of the agent is not in the navigation meshes. If that's the case, then we change its direction so that the agent doesn't hit the wall like an idiot. There is also a path curving algorithm, but it's still too early to know if we'll use that at all... We relied on this good document to program the steering algorithm. It's a 1999 document, but it's still interesting ... With the steering algoritm, we make sure that Buddy moves safely to his destination. (Look how proud he is!) So, this is the navigation mesh algorithm. I must say that, throughout my research, there weren't much pseudocode or code that described the algorithm as a whole. Only then did we realize that what people called "Navmesh" was actually a collage of algorithms rather than a single monolithic one. We also tried to have a cyclic grid with orthogonal cells (i.e. cells on the wall, ceiling) but it looked like that A* wasn't intended to be used in a 3D environment with flat orthogonal cells. My hypothesis is that we need 3D cells for this kind of navigation mesh, otherwise the heuristic value of each cell can change depending on the actual 3D length between the center of a flat cell and the destination point. So we reduced the scope of our navigation meshes and we were able to move an AI agent in our organic dungeon. Here's a picture : Each cyan cubes are the final waypoints found by the String pulling and blue lines represents collisions meshes. Our AI is currently still walking into walls, but the steering is still being implemented.
  24. When we started our game, we already knew it was going to be really abstract. Therefore, we also knew that, in term of shaders, it would be a real challenge. However, because we use jMonkey Engine (which is a shader oriented engine), we also knew that doing a custom shader with it was going to be a piece of cake. The Idea I used to be an avid TF2 player some time ago and I also started watching YouTubers TF2 just for fun. But the fact is that, surprisingly, some of these creators were trying to diversify their channel. Enter FUNKe, one of my favorite TF2 YouTubers. You see, he started as a normal TF2 content creator but later tried to diversify the topics of his videos. One of these videos was on the anime of Jojo's Bizarre Adventure. (I'm not a fan of anime but if I had to watch one, it will probably be that one) He said that the anime has a really abstract idea of color palettes: in some scenes, one character could be colored green while in the next, it is colored purple. That gave me an idea ... A Color Palette That Can Change The idea is to use a default color palette for each model and then, with a globally defined setting, dynamically change the specific palette used. In this way, we can change our palette according to the current level or even when events occurs in game. For example, this means that a sword can actively change its colors each time the player changes level. This can be really flexible. With some cleverness, we can make a truly abstract and unique game. In Practice All color palettes are stored on a single 512x512 texture where each pixel is a color. The coordinates are chosen according to whether the mesh is static or generated. Here's an example of a single palette: Keep in mind that it's zoomed in: each and every of these squares is supposed to be a single pixel. In our code, we load the material of the palette only once and apply it to almost all our meshes: paletteMaterial = assetManager.loadMaterial("path/to/palette/material/definition.j3md"); // The Palette material TextureKey atlasTextureKey = new TextureKey("path/to/palette/texture.png", false); m_atlasPalette = assetManager.loadTexture(atlasTextureKey); // The texture material For Static Meshes When we model our static meshes, we make sure that their UV mapping is properly aligned in the palette's texture in the appropriate pixel. Here is a simple sword model in blender. We can see that even though the UV map is really distorted, it fits well and is well aligned in the texture. Because our game is low poly and doesn't use detailed textures, there is no reason to ease these UV maps. In blender, there is a filter that changes the way our texture is displayed. Because we're going to change that in our code it doesn't really matter. We can actually fix that in our code, and it's very easy: // The Palette texture is loaded manually to overrite JMonkey's default filters paletteTexture.setMinFilter(Texture.MinFilter.NearestNoMipMaps); paletteTexture.setMagFilter(Texture.MagFilter.Nearest); We do that kind of UV mapping for (almost) all of our static meshes. For Generated Meshes Our game generates meshes that are used in our organic dungeon, but the UV mapping is quite basic... To make them compatible with our shader, we must explicitly modify the UV mapping of these meshes. Because our texture is actually an amalgam of all palettes, we have to take the first palette (which is our default palette) and use its UV coordinates to UV map our generated mesh. To help us with that, we made some enums that stores the UV coordinates of these colors. Technically speaking, in this case we use the middle of each pixel as UV coordinates. After having generated our mesh, we use a float buffer to store the UV coordinates of each of the mesh's triangles. That's why we need those enums. Here's the code we use to find out those UVs: public static FloatBuffer createDungeonTextureBuffer(FloatBuffer normalBuffer) { FloatBuffer textureBuffer = (FloatBuffer) VertexBuffer.createBuffer(VertexBuffer.Format.Float, TEXTURE_BUFFER_COMPONENT_COUNT, normalBuffer.capacity() / NORMAL_BUFFER_COMPONENT_COUNT); float skyUCoordinate = AtlasPaletteColor.SKY.getBaseTint().getUCoordinate(); float skyVCoordinate = AtlasPaletteColor.SKY.getBaseTint().getVCoordinate(); float soilUCoordinate = AtlasPaletteColor.SOIL.getBaseTint().getUCoordinate(); float soilVCoordinate = AtlasPaletteColor.SOIL.getBaseTint().getVCoordinate(); float wallUCoordinate = AtlasPaletteColor.WET_DETAIL.getBaseTint().getUCoordinate(); float wallVCoordinate = AtlasPaletteColor.WET_DETAIL.getBaseTint().getVCoordinate(); Vector3f normal = new Vector3f(); while (textureBuffer.position() < textureBuffer.capacity()) { normal.set(normalBuffer.get(), normalBuffer.get(), normalBuffer.get()); // Ground if (Direction3D.TOP.getDirection().equals(normal)) { textureBuffer.put(soilUCoordinate); textureBuffer.put(soilVCoordinate); } // Ceiling else if (Direction3D.BOTTOM.getDirection().equals(normal)) { textureBuffer.put(skyUCoordinate); textureBuffer.put(skyVCoordinate); } // Walls else { textureBuffer.put(wallUCoordinate); textureBuffer.put(wallVCoordinate); } } return textureBuffer; } With this, we can chose the UV based on the triangle's normal. The Shader The shader itself is quite simple. We took the generic shader provided with jMonkey Engine and added some uniforms and constants here and there. We take the dimensions of a palette (which is 8 x 5) and change the texture with this piece of code in our fragment shader: /* IN OUR FRAGMENT SHADER */ const int m_PaletteWorldWidth = 8; const int m_PaletteWorldHeight = 5; uniform int m_PaletteWorldIndex; // Later in the shader... ivec2 textureDimensions = textureSize(m_DiffuseMap, 0); newTexCoord.x += float(m_PaletteWorldWidth) * float(m_PaletteWorldIndex) / float(textureDimensions.x); We can then change the used palette by changing the PaletteWordIndex uniform in the code by doing this: // Palette Material is loaded manually to be able to change its PaletteWorldIndex value paletteMaterial.setInt("PaletteWorldIndex", paletteIndexUsed); // paletteIndexUsed is usually an Enum value Changing the palletIndexUsed value to a different one does that: And then we change the value of PaletteWorldIndex to 2: Although the colors are similar, they are also technically different. This can give us a lot of flexibility, but we still have to be careful: we still need to evoke the right emotions by using the right color at the right place at the right time. Otherwise, it can be harmful to our artistic style. We also need to maintain some visual consistency with the most crucial meshes. For example, our white crystal there could possibly be colored, and this color could be very important for the gameplay.
  25. SvelterEagle

    Java Code Review - Pong

    Hello, this is my first post here and also first time submitting my own code for review. I hear submitting code for others to see is a good way for you to improve and also see other solutions to problems, so here I am. I made myself a GitHub account and submitted my code there, which I guess is the proper way to submit code for others to see (?. Some background info: I'm a young adult and want to make a career out of game development. In my path to creating games of my own, I found the best way to learn bases is to copy already existing old games and understand their logic, so I started with Pong. (You can probably tell this won't be my last post here from that :P) Here is the github repository link (Pong). As I said, this is my first time posting and submitting code, so if I made any mistake, please tell. And thanks in advance to anyone helping me in this journey
  • Advertisement
×

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!