Jump to content

  • Log In with Google      Sign In   
  • Create Account

Khatharr

Member Since 24 Apr 2010
Offline Last Active Yesterday, 01:42 AM
-----

#5017571 Game programming help

Posted by Khatharr on 04 January 2013 - 06:05 PM

Working with a 3D world is more complex than working with a 2D world. You may want to try the easier of the two before you try to tackle the harder. It's just a matter of not overwhelming yourself with too much new stuff at once.

Design comes first. Build your design from the top down (in your head or on paper) and then start writing the code that will implement that design. Obviously you can't test much until you have that component built from the bottom up, so I usually start from the bottom and build a system outside of the main project, test it thoroughly and then import it once I'm confident that it's working.

You should know at least the general concept of how an API is used and it's a good idea to flip through the docs and see what all it offers, but trying to memorize the whole thing would be silly. Just use the documentation as a reference and you'll usually automatically memorize the stuff you use the most.

About linux IDEs... vi? O wait... lol I dunno. I only use bash on emulators. I'm sure there's some good ones though.


#5017287 Entity System

Posted by Khatharr on 03 January 2013 - 04:56 PM

Agreed. Typically an entity is any interactable object within the game world, so if your menu system is not integrated with the game world then you're probably better off separating them according to what belongs to the simulation and what belongs to the UI. There's no real rule, though, so if it makes sense to design your UI using entities then go for it. :)


#5016936 Program Wide Global Vars in C++?

Posted by Khatharr on 02 January 2013 - 08:05 PM

Using singletons in this case sounds more like putting duct-tape over a bullet wound instead of doing surgery, removing the bullet, and putting proper bandaging on.
wait_wut.jpg
Been there.


#5016916 Program Wide Global Vars in C++?

Posted by Khatharr on 02 January 2013 - 06:31 PM

I'd recommend reading those 'why singletons are evil' articles before you joyously leap into using them everywhere. There's some really good points made.


#5016494 Very early alpha of a retro 2D game -- keen for community critique

Posted by Khatharr on 01 January 2013 - 04:44 PM

You just throw player into some strange world.
I tryed to fight dogs. Then i saw some stuff on the ground.
Was chased by sceletons, run through upper door, see coast, pick stick, pick stick, run back - different place.
Same door - different place. And i'm dead. I love it, no jokes.

Almost sounds like 6 Days a Sacrifice, lol. Let's have a looksie...

Amassed an army of stray cats.
Acquired flamethrowers and discovered the OPness of the mighty BRANCH.
Defeated the restless dead.

Some problems I saw:
* Seems like pets wait for you to take damage before they defend you. I had like 4 HP and my army of cats would not attack the enemy because I had to run away lest I take any damage.
* WTH is going on with the timer?
* My inventory vanished consistently. I need a place where I can safely store more branches.
* Is the crafting system implemented yet? I dunno if that was just my inventory vanishing or if the system isn't there yet.
* I eventually ended up going up a staircase that somehow led underwater. I could not move and I seemed to be offscreen. There was a label on the top bar that said 'oxygen:' but there was no accompanying display.

It's fun to play with. Feels fast-paced without forcing you to play fast-paced and the exploratory "Gee, what's in THIS room? OMGOMGOMGOMG" style is something I miss from retro days.


#5016375 Cats in Video Games?

Posted by Khatharr on 01 January 2013 - 08:59 AM

<blockquote class="ipsBlockquote" data-author="3DModelerMan" data-cid="5016368"><p>Twilight Princess let you transform Link into a wolf also. The thing I always wondered how they did was animate the spine when your character turns. With a human, since they're tall and walk upright you can get away with just turning them sometimes, but not an animal like a cat or dog. I guess you could just add a small rotation to each of the spine bones depending on how far they turned.</p></blockquote><br />I don't have it in front of me, so I can't look at how they did it in that case, but for it to be natural I think you'd just apply the turn to the point between the front shoulders and use that and motion (walking forward/backward or hopping sideways) to influence the rest of the skeleton. It'd be sort of like the front legs are the active part and the rest is just getting dragged around.


#5016103 Quick and no doubt often repeated question...

Posted by Khatharr on 31 December 2012 - 11:02 AM

If you have 2 programmers you'll get 3 opinions.

C# supports DirectX, though if you disliked Java I'll warn you that C# is basically Microsoft's C-flavored answer to Java. YMMV

SDL has a C# flavor as well as C/C++, if you're interested in checking that out. It's really up to you to decide what you like. There's nothing wrong with SDL if you just want to make games with minimal fuss.


#5016071 Project start

Posted by Khatharr on 31 December 2012 - 09:05 AM


You don't need the professional version - the express version is perfectly fine for commercial projects, and isn't limited in the restraining ways most software 'express' versions usually are.


I already have Microsoft Visual Studio Professional 2010 and to my knowledge you are not allowed to release games with Visual Studio Express. At times I worked for a MMORPG Project as 3D developer and everyone was obliged to use Visual Studio Professional or higher because the licenses.



There are no such restrictions. It would be silly, since any identifying metadata in the binaries could easily be ripped (or you could just make the thing with VS and compile it externally).


#5015982 How does Multithreading Assembly work?

Posted by Khatharr on 30 December 2012 - 11:40 PM

Is cache management, like flushing a specific variable, is that manual?
 
Depending on the platform. You shouldn't have to mess with it in Windows, for instance. Platforms where it's useful will generally have API functions for managing it. It's only necessary when you have DMA going on and you have a situation where a DMA device may want to use memory that's cached on the CPU. It's actually quite rare, even in those situations. I think I only ever used it for the texture swizzle function and the texture hue-change function on aforementioned device. I just had to put a writeback call at the end of those functions and everything worked fine.
 
Interrupts can be signaled from asm. The instruction is INT on x86. http://pdos.csail.mit.edu/6.828/2004/readings/i386/s02_06.htm

(Edit - If you pick a fight with the thread scheduler the skeleton man will eat you.)
 
With the virtual memory model programs are more or less compiled as though they have exclusive access to the machine. The thread scheduler interacts with them from the outside. It's sort of like an emulator save-state. If you have the register states recorded and the memory recorded then you can restore both and resume execution as if there had been no interruption. VMM allows this because it can easily swap out pages for different processes, so each process basically has its own memory within the span of real-address-mode memory (or the swap file, depending on memory conditions). Since the stack for a thread is stored in that thread's stack page the register states can be pushed to that stack and then the stack page can be swapped to that of the next thread and the registers popped. This restores both the memory and the register states of the upcoming thread, so it continues as if nothing had ever happened.
 
When a PC boots it has a specific location that it looks to, usually on the primary disk volume, to find a startup module. The BIOS handles getting everything out of bed and then does basic loading to get the ball rolling. After that the startup module loads the OS and everything snowballs into place. On other platforms (like REDACTED that I was mentioning) the platform only runs one program at a time and the OS is just the first program to start. When it wants to run a program it places the path of the program in a specific place in memory then does a sort of soft-boot and the indicated program gets control of more or less the whole device.
 
Running an exe, the Windows loader does some pretty interesting black magic to map the different parts of the exe file into memory. The 'entry point' is calculated based on some values in structs near the beginning of the exe file. It's a pretty horrific mess in there TBH. You can read some about it here, but it may make you want to claw your eyes out. Basically the exe includes information about how big of a stack it needs and how big of a heap, etc. The loader gets it the pages it needs and then just sets eip to the entry point and lets it do what it wants. Sometimes it has to fiddle with some relative addresses within the file image in memory first, but VMM can usually eliminate that.
 
Just explain to me how I would, in assembly, instruct the computer to carry out two different threads at once.
How I would say something basic like "do A, B, and C in seperate caches.  when you've done A and B, do D."
 
That's more basic concurrency than threading. You'd mean 'cores' or possibly 'fibers' there rather than 'caches'. This is actually a better concurrency model than threading in many cases.
 
I'd really like to see what you're talking about implemented in C++, though I hear rumors that some compilers have custom features for it.
 
Starting an actual thread in ASM is no different than doing so in C/C++. You have to invoke the operating system's functions for it. I think what you may want in this situation is just a task queue that feeds into more than one thread for execution, but I suspect that you may not get the results you're looking for. The thing about the Windows thread scheduler is that Windows usually has a pretty large number of threads running all over the place. It's not just the program in the foreground that's getting scheduled. The kernel needs to do work, programs in the background are doing work, etc, etc. So even if you split up work using threads you're not really getting pure concurrency since those threads will basically execute when they damn well please. Your work won't necessarily be paralleled and you'll probably end up waiting on results when you don't need to.
 
In other words, you may be a little ahead of the state of the art there, but people are working on it. If anyone knows about these rumored compilers that offer keywords for concurrency I'd like to know about them as well. biggrin.png


#5015888 A Game's Structure

Posted by Khatharr on 30 December 2012 - 05:11 PM

Ah, I sort of expected that this would be the first thing you asked about. What you're looking for is a "state manager". Rather than just using one huge loop you create 'states' or 'scenes' (depending who you talk to - they're the same thing) that get plugged into the main loop. The logic for the section you're in is inside the state/scene.
 
I think L.Spiro wrote a nice article about it... Hang on a sec...
 
Yeah, here we go. I was looking over this while I was fiddling with my scene manager a while ago.
 
http://lspiroengine.com/?p=351
 
As for different stages/levels you can break them into data units (the map and resources, etc required for that stage) and then have your map state/scene load the data unit, run with that data until you move to another one, then just unload the current one and load the new one.
 
This forum formatting bug is killing me... -.-


#5015876 Which of these two options is best?

Posted by Khatharr on 30 December 2012 - 04:08 PM

Aye, some guru once said something like, "The fastest and most error free code is that code which is never written."

The idea being that reducing work by having good structure is very nearly always better than optimizing the individual routines. In production code it's almost a sin to try and low-level optimize something that a profiler hasn't singled out and can't be refactored out. If you're getting paid to code something and you spend 5 hours on an optimization that gets factored out the next day you just wasted 5 hours of paid work. Sometimes I'll get 'the bug' (in my brain) and optimize something until it's ridiculous, but I always do so knowing that it's a pointless exercise, and I usually think up several ways to factor the code out even while I'm in the midst of my madness.

I posted something a while ago about an xor encryptor that I was playing with (it was making my hard disk stall and make a weird grinding noise). I optimized it by actually compiling bytecode for the encryption at runtime and then executing it, which is ridiculously fast, but the fact is that the choke-point in that app is the disk IO. I knew from the start that if I were to run the old (non-optimized) code while the app was async reading into the next buffer it would completely mask the encryption time, resulting in better performance without the tomfoolery. I just wanted to play with assembly for a while.


#5015863 A Question From An Absolute Beginner...

Posted by Khatharr on 30 December 2012 - 03:35 PM

I would totally play that game.




#5015861 How does Multithreading Assembly work?

Posted by Khatharr on 30 December 2012 - 03:20 PM

Ah, instead of trying to respond to each question individually I'll try to walk through threading on a single core. Then it's easy to see how additional cores can easily be added.

 

First let's talk about the general layout of a single-core CPU.

 

You have the ALU, which is the 'brain' that does the actual work, such as adding and subtracting or etc. When an electrical pulse hits the CPU the current instruction that's loaded into the instruction stream is used as a set of on/off gates that control which parts of the ALU get triggered. On bits pass on current and off bits don't. That current passes through the ALU and causes some change in the internal state of the CPU based on what instruction is being processed. Attached to the ALU are the CPU's registers.

 

The CPU will have several registers, depending on what type it is. If a CPU is said to be 32-bit that means that each GPR (general purpose register) is 32-bits in length. A 64-bit CPU has 64-bit registers, etc. On an x86 you have 4 registers to play with data: eax, ebx, ecx, and edx. They have different uses depending on the situation (which instruction you want to execute), but you can more or less load or store data to them as you please. In addition to these there are some other registers for special uses:

 

(These four are also considered part of the GPR and can be accessed directly by 'mov' instruction.)

ESP - extended stack pointer - points to the top of the stack

EBP - extended base register - points to the base of the stack (the point at which the current function's stack space begins... sort of)

ESI/EDI - extended source/destination index - used for making memory transfers or other looping memory tasks more efficient. Some instructions use these to loop through memory in either a forward or backward direction. Can be very useful in such situations.

 

Special, non-GPR registers:

EFLAGS - This register is used as a set of bits that indicate the state of the CPU. Instructions can set the different bits or react to the state of them, but direct access to EFLAGS is not possible (you can get at it, but it takes some foolery).

EIP - extended instruction pointer - points to the memory location of the next instruction to be executed.

 

Segment registers:

These registers are not as commonly discussed, but have to do with the virtual memory management model. Essentially there's a few registers that can be used to point to a specific location in memory, called a 'segment' or 'page'. When the CPU is in virtual memory mode and gets an address, that address refers to a memory offset within one of those pages. Generally one page will point to the memory image of the module (the exe or dll being executed), one will point to the stack, and one will point to the heap. Others can also be available depending on the program. Windows calls these 'pages' and has a set of functions for managing them. Pages can have read/write/execute permissions set and will throw an exception if those permissions are violated, such as good old 0xC0000005 aka the segfault (segment fault - get it?).

 

There are also SIMD registers on most modern CPUs. These tend to be larger than the GPR and are often also used as the floating-point registers. They implement things like SSE or MMX and the like.

 

A simple ASM program to add 1 to a variable looks like this:

 

mov eax,variable #load the value of 'variable' to the eax register

inc eax #increment (increase by 1) the eax register

mov variable,eax #store the value in the eax register in the memory belonging to 'variable'

 

This is where the cache would come in. When the CPU wants to read a value to memory it sends a request to the system bus. The bus interprets the request, finds the memory and sends it back to the CPU. This takes several CPU cycles to do, so the CPU ends up spending most of its time waiting for the value to arrive before it can continue. In order to solve this problem modern CPUs have an onboard cache. The CPU tries to predict what memory you're going to want and ask the bus for it ahead of time. Then when you go to load the value it's (hopefully) already on hand and you don't have to wait for the bus. Changes to the value are stored in the cache until the CPU determines that you're done with that data, then it flushes it back to main memory. On systems where more than one device have access to main memory this can cause problems, since the CPU can work on some data and then still have it cached - the other device may look in main memory and not see the changes that haven't been flushed from the cache yet. The 'volatile' keyword in C/C++ prevents the cache from holding the specified data. It always reads that data from main memory and always writes changes to main memory. The instruction stream typically doesn't need to know anything about what the cache is doing except in those cases. The cache more or less takes care of itself. (It actually reads the results of the CPU's operations in order to try and decide which instructions/data should be pre-fetched.)

 

A brief look at the stack comes next. To enter a function you typically use the 'call' instruction and give it an address:

 

void myFunc(char* message) {
  printf(message);
}

int main() {
  char myStr[] = "Hello.";
  __asm {
    push myStr;
    call myFunc;
  };
}

When a process starts it allocates a section of memory for the stack. The base pointer and stack pointer are set to the end of that memory. When a value is 'pushed' it gets written to the location pointed to by the stack pointer, then the stack pointer is reduced to make room for the next value. So if I say 'push eax', the value in eax gets written to the address pointed to by ESP, then ESP is reduced by 4 (meaning 4 bytes). When I say 'pop eax' the stack pointer is increased by 4 and then the value it points to is placed in eax. Memory which is at an address lower than ESP is considered 'invalid'. It can contain anything at all and should not be referred to unless you're doing something weird.

 

To call a function, first the arguments are pushed in reverse order, then the 'call' instruction is used. 'call' does the following:

 

push EIP to the stack (store the address of the next instruction - the one after the 'call')

jump to the label/address provided as an argument to 'call' (in the example it was the label 'myFunc')

 

The function called will usually set up its 'stack frame' like so:

 

push ebp (push the current base pointer to the stack)

mov ebp,esp (set the base pointer to point to the current stack pointer position)

sub esp,??? (where ??? is the total size of the function's local variables)

 

So what just happened there?  Well, ebp gets pushed. This gives us a value to set it back to when we exit the function.

Then we set ebp's new value to the current stack position. This means that ebp now points to the previous frame's ebp. If we need to unwind the stack we've got a chain of pointers that all point right down the chain to our original ebp.

After that we subtract the local storage size from esp, meaning that we've reserved space for our local variables on the stack. The compiler knows which address in that space belongs to which variable.

 

At this point the following is true:

  • The function arguments begin at ebp+8 and increase upward (since we pushed them in reverse order prior to 'call')
  • Local variable storage begins at ebp-4 and increases downward
  • Local storage is not necessarily in the order of its C declaration. The compiler is free to order things how it wants within the stack frame.

Once the function is done it wants to return control to the caller. It does the following:

 

If there's a return value then place it in the eax register

Move the value in ebp to esp - this puts the stack pointer back at the point it was at when we entered the function, effectively freeing the stack frame's memory

Pop the stack into ebp - restore ebp to the value it had prior to 'call'. now it points to the base of the caller's stack frame again

 

'ret' - this instruction basically pops into EIP, moving the instruction pointer to the position of the instruction after our original 'call'

 

At this point the arguments that we pushed prior to 'call' would still be on the stack. There's two ways to handle this:

 

Provide a numeric argument when calling 'ret' - This value will be added to ESP after EIP is popped, effectively freeing the pushed args.

 

Just manually add the length of the args to ESP after the function returns. - This has to be done in cases where the length of the args is unknown to the function, such as in the case of printf, which can have a variable number of arguments.

 

Okay, so that's very complicated unless you just sit there and watch it in action for a while in the debugger.

 

Now we're almost to threading. The next concept is interrupts. A program (such as the thread scheduler) can set up a series of instructions in memory and then tell the CPU to register the start address there as an interrupt routine. The routine is matched to an interrupt number and remembered until the CPU is told otherwise. When the CPU gets an interrupt signal it will have a number accompanying it. The CPU records all registers, including EFLAGS, EIP and the segment pointers, then transfers control to the routine matching the interrupt number it just got. When the interrupt routine is done it restores all the registers and the program resumes.

 

So you may now have a notion of how a thread scheduler will work. A routine is set up as an interrupt routine, but instead of returning to the interrupted thread it saves the register state and then returns to the state saved from the thread that's scheduled next. Interrupts can also be set to trigger on timers, which makes threading easier to implement.

 

In the case of a multi-core system the scheduler just has the option of choosing which core to interrupt and give the next thread to. Apart from memory access concerns the cores don't really need to know anything about one another. They just keep executing the instruction at EIP until they get an interrupt.

 

All that's somewhat simplified, though. There's a lot of tiny details and craziness that goes on in there that can keep you busy for many sleepless nights.

 

Still, it's fun, right? biggrin.png




#5015648 Ouya Compiler

Posted by Khatharr on 29 December 2012 - 11:10 PM

*Looks in wikipedia*
 

(developer models ordered during the Kickstarter campaign for $699 or $1,337 will come pre-rooted)


LMAO

Props to Google for allowing rooting without voiding the warranty. Looks like they're gearing the whole console toward indy developers. Best thing since Pandora.

Ah, it says the dev release was yesterday... Let's mosey on over to their site and have a looksie...

http://www.ouya.tv/devs/

Looks like they're just adding an additional API to the Android kit. They seem to be targeting Unity developers primarily. There's mention of Eclipse. C++ is also mentioned.

 

C# also mentioned.




#5015509 Tutorial for making a side-scrolling gravity character

Posted by Khatharr on 29 December 2012 - 01:13 PM

How familiar are you with Newtonian physics? (Specifically the nature of force and inertia.)

 

Apart from basic physics it's just a matter of good collision detection.

 

Someone linked to this recently:

 

http://www.gamedev.net/page/resources/_/technical/game-programming/the-guide-to-implementing-2d-platformers-r2936

 

I found it to be a good article.






PARTNERS