Jump to content

  • Log In with Google      Sign In   
  • Create Account

JTippetts

Member Since 04 Jul 2003
Offline Last Active Today, 02:54 AM

#4994550 Is it possible to draw Bezier curves without using line segments?

Posted by JTippetts on 27 October 2012 - 04:08 PM

I understand that I can subdivide the curve down so that I am drawing single pixel lines, but that is again drawing lines. What I am looking for is Bezier curve code that draws a Bezier similarly to Bresenham's line drawing code. In other words, the initial pixel is calculated and the rest are incrementally derived from some function. The curve would be plotted pixel by pixel by pixel.

My interest in this is really just personal. I have no need for it, but it always bothered me that I could not find any examples. I am just really curious if this has ever been done, and if so, I would like to see the code.


Well, if your line segments are only a single pixel long they're... uh.... just pixels. They're sequentially plotted from the function that is the Bezier curve. You're probably not going to find something as simple and elegant as a Bresenham algorithm for Bezier curves because the curvature is neither constant like a circle, nor easily predictable like an ellipse. You could possibly derive it to obtain the curvature (the curvature can be described as the rate of change of the tangent to the curve with respect to the arc-length, or dT/ds) and match curvature to a pixel pattern, but that just seems needlessly complex. Some quick googling turned up http://www.gamedev.net/topic/156180-curvature-of-a-bezier-solved/ in which a poster posted about how to find the curvature of a Bezier; couldn't say how accurate or correct it is, but it might be a place to start. Seems like, if you know the curvature at pixel N, then you should be able to use it to calculate pixel N+1. But, again, it's probably just easier to evaluate the curve for very small increments of t instead.


#4994546 Are you planning/making a Windows 8 (metro) app?

Posted by JTippetts on 27 October 2012 - 03:59 PM

I am actually planning to stop programming when 9 comes out. I don't like gatekeepers, and when they're forced on me, I'll find something else to spend my time on. The field is moving on, going into places I'm not comfortable following. Just getting old, I guess.


#4994479 Are you planning/making a Windows 8 (metro) app?

Posted by JTippetts on 27 October 2012 - 12:48 PM

You forgot "hell no."


#4994136 Ethics of Placeholder Art

Posted by JTippetts on 26 October 2012 - 07:46 AM

I find it odd that anyone would need comments on their interface if it was using placeholder anyway. Wait until you have elements of your own before you show it off, otherwise it only means that the original design team did a good job, and you know how to copy paste. What's the point of that?


#4993980 Codeblock ISO scoping problem

Posted by JTippetts on 25 October 2012 - 06:41 PM

You have a semi-colon after your for(unsigned int q=... line, which terminates the loop at the line, rather than looping through the block. Everything in the block that tries to use q then violates the rule that you shouldn't use a variable declared locally to a block or loop like that after the loop terminates. Also, later, you try to reference i, which doesn't exist. (Probably need to change that to q, after you eliminate the semi-colon).


#4993978 What's the deal with IDE's?

Posted by JTippetts on 25 October 2012 - 06:33 PM

Define "too often". I've used C::B for a long time, five or six years, maybe longer. Never had a crash. Now, I'm sure it does crash, but most modern software is relatively unstable. Just save often. That has been a good guideline to follow for decades.


#4992162 [Open source project] Voxel based mesh generator

Posted by JTippetts on 20 October 2012 - 08:42 AM

C:\Python33>python knot.py
Traceback (most recent call last):
File "knot.py", line 2, in <module>
from vBaum import *
ImportError: DLL load failed: %1 is not a valid Win32 application.


ummm


Looks like the pre-compiled binary is 64-bit, but your python is only 32-bit.

@LordOfTheBytes: Looks pretty cool, I'm going to check it out.


#4991425 Texturing a procedural Icosahedron

Posted by JTippetts on 18 October 2012 - 07:46 AM

Have you looked into procedural solid texturing?

Basically, instead of generating a bunch of 2D textures and trying to project them onto the icosahedron, you would construct a 3-dimensional function, evaluated on a point (x,y,z), that would return texture information for that input point. Then you could rasterize triangles in the UV map, and for each triangle you would interpolate the 3D positions of the vertices and pass the interpolated values in to the 3D function. An example:

Posted Image

An icosphere with a crude UV mapping.

Posted Image

A basic F2-F1 cellular 3D function baked to the texture map.

Posted Image

The icosphere shown with the UV texture mapped on it.

This way, instead of having to manage 10 separate textures you simple "bake" the data directly from one solid texture to a single UV texture. If you create your UV mapping more intelligently than I did for this example, you have less texture waste.


#4991329 [SFML] I Finished Breakout! It's So Awesome!

Posted by JTippetts on 17 October 2012 - 10:22 PM

Congratulations on finishing this thing, and thanks for coming here to the forums and being excited about this stuff. I have a tendency (like many others, I suppose) to be all jaded and even bored about a lot of this, so it's nice to see someone who is enthusiastic and all fired up.

Anyway, my thoughts (somewhat random):

1) Source Releases

Your source-only release contains a lot of compiled binary .obj files, as well as DLLs and pre-compiled headers that greatly inflate the archive file size. For smaller downloads, source release packages should be stripped of any binary data like this. All of that stuff is generated in the compile process, so no need to ship it.

2) Resource Management

As you move on to more complicated projects, you are going to want to be smarter about how you handle resources such as images. In your program, the block, paddle and ball textures are loaded and used essentially as globals (not technically, but their usage patterns are global). That is, you create an essentially static object that exists for the lifetime of the program, and is handed to objects that need it.

In a more complicated program, though, that uses more assets, it is impractical to have all assets loaded for the lifetime of the program. You will instead want to implement a system for managing the lifetime of objects such as textures/images. An object can request a resource from the system, and it will load it (if needed) and return a reference or pointer to the asset. When the object no longer needs it, it is released. If no objects are referencing an asset, it can be unloaded. You can also implement a cache system that will keep some objects loaded if they are frequently used.

As an example of this, one of my earlier systems used an internal std::map of weak_ptrs keyed on a string (and later a hashed string). The string key can be filename, and the weak_ptr points to a texture resource. When a texture is requested, the system first checks to see if there is an entry in the map for the requested file. If so, then the weak_ptr is checked for validity. (If a resource is dropped, an entry will remain in the map, but the pointer itself will be invalid). If the pointer is invalid the resource is loaded. If the resource does not yet exist, it is loaded and a weak_ptr to it is placed in the map. Once the resource is located and loaded as needed, then a shared_ptr is cloned from the weak_ptr and returned.

As long as at least one shared_ptr exists, the resource will remain loaded. Once all objects holding a pointer to the resource are destroyed, though, and no shared_ptr exists, then the resource destructor is called and the resource is destroyed, the weak_ptr i the table invalidated. Requesting the resource, then, will cause it to be reloaded. You can implement a second map of shared_ptrs, keyed on name, as a cache to hold a copy of the resource and keep it from being dumped if all other shared_ptrs are dropped.

If you are anything like me, you will go through several iterations of your system until you get something you like, however you implement it. And if you are even more like me, this will be one of your first "reusable" systems that you drag with you from project to project, iterating and improving it as you go. Nailing this system down will vastly help you later, though, as you try to tackle more complicated projects.

3) Sneaky Side Effects

Take a look at your Block::Initialize method. The name suggests that the method will set some internal invariants and data in Block then exit. There is no reason to suspect it does anything else. Yet it has a side-effect, in that it takes references as parameters, and modifies the value of one of them. This sort of sneaky side effect is generally regarded as a Bad ThingTM. Even if the side-effect is documented (it isn't) this is still something you should avoid. Either rename the method to reflect its actual behavior, or refactor to eliminate the side effect and find another way to accomplish what you need. Trust me, if you ever come back to this kind of code after a 6-month break during which you worked on something completely unrelated, these kinds of side-effects can cause you no end of headaches.

4) General Inconsistencies in Object Handling

Your Block class has an Initialize method, but neither your Paddle nor Ball class do. Ostensibly, they are all game objects, and ideally you would want at least some semblance of a common interface for dealing with them. In the past, people did this by implementing great, gawky, god-awful object inheritance hierarchies to abstract the handling of game objects. Current, modern thinking is to implement object composition, where the shared components have common interfaces. However you solve it, you should have some consistent, data-oriented means of creating, managing and destroying objects.

Implementing a sane object management policy means that you can, for example, destroy blocks that are hit, as opposed to just setting an internal flag to hide them. You can also spawn intermediate objects that perform assitance tasks, as well. For example, when a block is hit you can spawn an Explosion object whose sole purpose is to exist long enough to play an explosion animation and a sound effect, then self-destruct. The spawning of this object can be initiated by the block collision logic.

It's kind of... weird... that you implement your logic updates as functions. Really, object logic probably belongs inside the object itself, via some sort of Update method. An external function would iterate on objects and call their Update method. This way, you can implement different brands of logic merely by instancing different varieties of objects, and the main loop doesn't have to be modified to call another function. It can just keep calling Update as before.

Things such as collision detection are typically off-loaded into sub-systems of their own. For example, a physics sub-system. The sub-system will keep arrays of primitives and when a method is called, it will iterate the arrays in some fashion (this can get complex, for systems with lots of objects, but for small games it can be dead simple) and calculate collisions. It will determine which objects collide with each other, and it will somehow notify the interested parties of the collision so that they can update themselves accordingly. Then the main loop can just call UpdateCollisions after Update.

Again, as with anything, there are a thousand ways you can handle this stuff, but keeping essentially global references to all objects is not the optimal method.

5) Ball::SetVelocity

Huh. Why would a method named SetVelocity (which you would expect to accept as parameters a 2D velocity vector) accept a string parameter instead? I mean, I get what you are doing, but it just doesn't seem like the best way to do it.

6) Main Loop

There are problem with how you implement your loop. Moving things have a fixed, specified velocity which is applied each turn through the loop, but the loop doesn't take timing into account. It will run as fast (or as slow) as the CPU will allow. This means that if there are background tasks, for example, that pull away CPU time the simulation will slow down. It will also run faster or slower depending on the CPU speed. In the old DOS days, many games were implemented like this because the hardware at the time was all fairly similar. But once faster processors came around, many of those games became flat out unplayable, due to extreme speeds. It is generally a bad idea to allow your loop to run "unrestrained" like that.

As with everything else, there are a number of ways you can implement a proper game loop. Some loops will fix the logic update rate to a clock, and allow it to render as fast as possible, interpolating logical positions to make the visual update smooth. Others will update each time through the loop using a calculated elapsed-time delta to scale velocities based on how much time has passed since the last update. Still others will do one or the other of these, and limit the visual framerate to some rate in order to keep from hammering the video card too hard. What you do is a matter of taste, but I highly recommend you do a bit of research into it.

These are just a few of my first impressions upon looking at your code. Don't be discouraged if it seems like a lot. You've got plenty of time to figure all this stuff out, so just keep plugging away and trying to improve and you will get there. :D



#4991000 Retro Art Design or Laziness?

Posted by JTippetts on 16 October 2012 - 10:09 PM

Many indies certainly are going with "retro", simply because it's easier to make. There is nothing wrong with that at all. If you're a small studio on a small budget, sometimes you have to work with what you have. Especially a one man team. If it comes down to using easy-to-make graphics and releasing, or trying for expensive and flashy graphics and never releasing, the choice is easy. Art and graphical assets are frequently the most expensive and time-consuming part of making a game. I haven't spent even a tenth of the time coding Goblinson Crusoe as I have struggling with the artwork, and there is still so much more to do that frankly the thought of it is quite daunting. Even on games with the budget to hire out, you are still going to have a lot invested in the artwork alone. When you are looking to trim the budget, you need to look first at the largest expenditures, and in games that category includes the artwork.

One of the things I find neat about indie games, is the fact that you don't have to have flashy, expensive graphics. That was always the driving force of the AAA arc: who can release the "next gen" game, with the flashiest graphics. It resulted in what are, in my opinion, extremely empty and soulless games made on multi-million dollar budgets. I remember during the 2000s, I spent a lot of money on buying the latest games, hoping that amongst all the flash and glow there would be a good game. I remember that almost without fail I was disappointed. I also remember (very recently) buying Dungeons of Dredmor, which is quite retro in appearance. Not a single big-buck AAA game I have ever bought has ever provided me with as much sheer enjoyment as DoD did. I thank the heavens that they did not opt to go with flash and fancy and expensive, and instead opted for the "easier" retro style, or the game might never have seen the light of day.

It is a tough line to walk, though. You need to balance ease of asset creation with making a good visual impression. I admit that a great many indies do, sadly, fall down there. There are plenty of indie games that I have passed over simply because I did not like the visual style, so it definitely makes a difference.


#4989947 Can any game be truly better than another?

Posted by JTippetts on 13 October 2012 - 08:15 PM

You're right, no game ever made is better than Big Rigs: Over the Road Racing.


#4989348 Being a tester for reasons of getting your foot in the door?

Posted by JTippetts on 11 October 2012 - 08:33 PM

If you want to get your foot in the door to become a professional QA guy then sure, go ahead. If you want to get in as a developer, you'd be better off going for a developer job. There are entry level developer positions just as there are entry level QA positions, and your odds of moving up the developer chain would be vastly higher if you were, you know... a developer. I'm sure some folks do move up from QA, but I've never heard that to be a significant number, and if you end up demonstrating ability and skill, a lot of companies would be delighted to keep you in QA to ensure that they have good people there. Because it is important in its own right, and not just as a stepping stone to other fields.


#4989095 Double to Float

Posted by JTippetts on 11 October 2012 - 07:37 AM

Just wanted to chime in, probably a bit late but anyway. Floating point variables have a range of something like 1234510. Although this is difficult to place actual range of numbers to it is important to remember that floating point variables are normally used for positions, velocities and other 3D calculations. It is very rare that you will ever encounter a level map, model, mesh or really any 3D asset that even comes close to peaking out the maximum allowable values of a float.

With all of that said I understand that many coders think bigger is better and that using a double in place of a float will give you the ability to have larger maps, worlds, more precision in game and all that jazz. However that is simply untrue, video cards themselves fall flat on their face when you get anywhere near those sizes. So I guess in short, I would suggest coders just be in the habit of using floats unless there is some extenuating circumstance wherein you actually do need the extra range.


I believe that the developers on the original Dungeon Siege encountered precision problems while building their continuous world, hence their switch to a hybrid system using chained local coordinate spaces. It really isn't as hard as you might think to start encountering precision problems using single-precision floats. Awhile back, I built a quick and dirty little streaming system for my isometric game, and it really only took me about 20 min to hit the "end of the world", where precision problems started cropping up. You can have large floats and you can have precise floats, but large precise floats are a different story.


#4988957 Double to Float

Posted by JTippetts on 10 October 2012 - 10:44 PM

It's been awhile, but I think there are possible ramifications with having DirectX use float rather than double. I seem to remember having an issue once when I was playing with Ogre3D, where I was suddenly, seemingly out of the blue, getting weird and intractable errors with my embedded Lua. Spent days trying to figure it out; it only happened when I would switch to a Direct3D renderer from OpenGL. I believe it was DirectX changing the FPU mode to float, whereas Lua wanted doubles. Things could be different now, though.


#4988929 Bullet misses the enemy

Posted by JTippetts on 10 October 2012 - 07:46 PM

Some time back, there was another discussion about this topic:

http://www.gamedev.n...ng-their-shots/

FLeBlanc runs through the math to calculate the point you need to aim at using a quadratic equation, assuming there is a point you can aim at that will possibly hit the target. Note that sometimes there just is no solution.

Edit:
Eh, just re-read and noticed you want tracking bullets, rather than target leading. In this case, it becomes a sort of tradeoff. How tightly do you want them to track? The way you have it currently, you calculate a trajectory for the bullet based on the vector from the tower to the enemy, but then you add this vector to the existing velocity vector. This will give you an accurate heading initially, but as the trajectory diverges away from a straight line the new velocity vector has a harder and harder time trying to correct out the old, now-incorrect velocity with the new heading, so the bullet just goes more and more awry.

If you want the bullet to tightly follow the enemy, then each update just replace the old trajectory with the newly calculate trajectory. However, this could result in some pretty tight curves. If you want to limit the curves, then you can calculate some vector that lies in between the old velocity and the new velocity whose angle relative to the original velocity is no greater than some limit, A. Then set the velocity to this new vector. This way, the bullet will loop around and eventually spiral in on the target, without sudden and drastic changes in direction.




PARTNERS