[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference hydra::amiga_v1

Title:AMIGA NOTES
Notice:Join us in the *NEW* conference - HYDRA::AMIGA_V2
Moderator:HYDRA::MOORE
Created:Sat Apr 26 1986
Last Modified:Wed Feb 05 1992
Last Successful Update:Fri Jun 06 1997
Number of topics:5378
Total number of notes:38326

5090.0. "Game development in C" by WHAMMY::spodaryk (For three strange days...) Tue Oct 01 1991 17:03

I'm tossing around ideas for writing some type of "shoot-em-up" game for
the Amiga.  I know there are probably plenty out there, but this is more
for personal fun/education than anything else.  Naturally, the game will
peacefully co-exist with other applications and properly use/free resources. 

I'm mentally formulating a very object oriented, FSM driven game, and I'm
wondering how best to schedule small tasks such as "move object X to Z pos",
etc.  Can that type of work be done in a 'task', or is it best to build
some simple scheduler that will run within the current process?  I believe
there are I/O restrictions within a task, but I have to do more research.

Another bit I'm thinking about is how to perform "background" tasks,
without interfering with the current gameplay (ie. music, scrolling background,
etc).  My current thought is just to create an entirely seperate process,
which can take requests from the "main"/game process, and act on them.

Actually, that scheme might work out well for much of the game.  I could
have a process that handles user input, another for craft movement, one process
that handles "enemy" movement and gameplay, and other processes for music,
sound effects, etc.  They could coordinate efforts just using basic msgport
communication.  Performance should be reasonable with this "local" type comm.

This may all work out easier than I had hoped.  Does this seem like a 
reasonable scheme, and has anyone done similar?  I'd appreciate any/all
input, and I'll continue to formulate a general design.  There's probably not
much sense in building much of a scheduler, since the Amiga is designed
to do that for me!

Steve
T.RTitleUserPersonal
Name
DateLines
5090.1TENAYA::MWMTue Oct 01 1991 17:3918
Well, as someone who doesn't build arcade-style games, it seems reasonable
to me. I'd worry about not having enough control over task scheduling, but
that's about it.

You probably want to use tasks for most things, instead of processes. The
I/O restrictions on a task are that it can't call dos.library (dos.library
needs data that's in the process extension to the task structure). For what
you're talking about, you probably don't want to call dos anyway (disk
I/O from a task pushing a sprite around?). Tasks are cheap enough that
using one task/moving object is probably reasonable.

I do know that the real high-speed, super-spiffy games tend to synchronize
things to the video beam. That level of cooperation may not be possible with
lots-n-lots of tasks.

It does sound like an interesting probject; keep us posted...

	<mike
5090.2Machine code is best!GIDDAY::MORANWed Oct 02 1991 09:2014
    Unfortunately unless you really need to make this Multi-Task your first
    two lines of source code will be Forbid() & Disable() !!
    
    AmigaDos tend to interrupt your games at the wrong times with result in
    jerky looking movement on objects.
    
    You'll be best to do verticle interupts for timing things. You work out
    the timing of your game in the amount of scan time left. eg the music
    will be played from scan lines 250-300. This way you can make sure that
    you not updating the video data whilst it's being displaed by the amiga
    hardware.
    
    Shaun.
    
5090.3"best" for what? :^)WHAMMY::spodarykFor three strange days...Wed Oct 02 1991 14:2816
Thanks for the info.  I believe that 'tasks' are precisely what I need.
I remembered there were some restrictions, but since the tasks will be
performing very finite functions, it shouldn't be a problem.

Hopefully, I won't have to write much assembler.  It's a valid way to
get good performance/synchronization, but I'd like to avoid it.  I'll
write it thinking "high-level", and if it ends up being jerky/etc, then
those problems can be addressed.

I'm trying to think of it such that the pieces could be migratable to
platforms that provide some type of threads support.  We'll see if decent
games can be written without banging the hardware.

Keep those ideas coming....

Steve 
5090.4TENAYA::MWMWed Oct 02 1991 18:1513
If you're using SAS/C, you can do vertical interrupt timing type things
without resorting to Assembler. You declare your function as __interrupt,
and you can then pass it's address where you'd normally pass a pointer to
assembler.

If you're going to run for long periods of time with interrupts disabled,
you probably ought to disable the OS and force a reboot. The system software
isn't reliable under those conditions.

On the other hand, Forbid()'ing task switches is safe, and may do the job.
Just provide a pause mechanism that turns things it back on.

	<mike
5090.5Ohh, you want to retarget!CVG::PETTENGILLmulpWed Oct 02 1991 23:3110
After downloading the AMOS 3D demos which includes a shoot'em'up, I was
impressed with that.  Maybe they'll retarget AMOS again; what other platforms
are you interested in?

One thing that I find a little puzzling is that you talk in terms of threads
and as far as I know the machines that are being targets for thread support
all run X Windows, which includes its own thread support.   There are lots
of reasons to integrate X threads with CMA or POSIX threads, but for a game
it isn't clear why you would need thread support outside the GUI support.
Unless it was going to be use network or file system I/O extensively.
5090.6X as a game platform - Nahh!WHAMMY::spodarykFor three strange days...Thu Oct 03 1991 13:4141
Well, it's very true that tasks/threads aren't necessary for writing games.
However, it seems (to me) that they would be quite an advantage.  Each
task/thread can perform a highly specialized function, which will keep
managing things simpler.

Right now, I envision the MAIN process as handling user input and passing
some of that on to the SHIP task, which will act according to the input
(up, down, left right, fire, etc).

The MAIN process will also create other tasks, such as ENEMY tasks.
Each ENEMY will have some built in strategy (ie. fly around, firing 
missles, etc)  Firing a missle will create a MISSLE task, whose function
is to move forward, and check for collisions.  Once the missle is launched,
the ENEMY shouldn't be too concerned with it's actions, but some reporting
can be accomplished.

A collision will cause the task to signal the other task involved, who can
then take action (ie. blow up, update score, etc).

Any of the various tasks can signal a SOUND-F/X task to perform a specific
sound (ie. explosion, beep, boing, etc)  The SHIP task shouldn't have to
worry about wasting time making noises when it can just tell another 
specialized task to do it.

Naturally, some tasks will need to communicate with other tasks - primarily
using signals for simplicity and performance.  More complex communication
can be done with MsgPorts.

I can imagine the MAIN process creating the various tasks and being notified
of specific actions.  It will use those actions (signals, messages) to determine
how play should proceed and what ENEMY tasks should be created.  It won't have
to worry about moving around sprites, performing sound, etc.

It's hard to explain, but I think architecturally it will work out great.
It remains to be seen what type of performance or playability can be 
achieved with such a method.  I don't really plan on moving it to other 
platforms, but try to keep portability/migration in mind for everything.

The way I work on these non-work projects - it'll probably never be finished...

Steve
5090.7CRBOSS::QUIRICIThu Oct 03 1991 13:5212
    re: .6
    
    sounds like tasks are the way to go; but you do, i think, need some
    way to synchronize 'em relative to the real clock, or at least, the
    real clock as your game 'thinks it is'. If you aren't going to use
    interrupts based on horizontal scanning, maybe your intertask
    msgs could include what time it is, relative your 'game clock'?
    
    Like, the missile could look for 'events' happening in the time
    interval it knows it's currently on?
    
    Ken
5090.8Jerkiness Rarely A ProblemTLE::RMEYERSRandy MeyersThu Oct 03 1991 15:4317
Re: .2

>    Unfortunately unless you really need to make this Multi-Task your first
>    two lines of source code will be Forbid() & Disable() !!
>
>    AmigaDos tend to interrupt your games at the wrong times with result in
>    jerky looking movement on objects.

Please don't Forbid() & Disable().  I have a few public domain arcade
type games on my system that run with multitasking enabled.  The "jerkiness"
factor is far, far overrated.  I wouldn't ever run these games if they
turned off multitasking.  I use them to kill time during downloads or
long compiles.

One of the games, a missile command clone, is normally so fast that the
only way for me to play it is to slow it down by running something
simultaneously with it.
5090.9WHAMMY::spodarykFor three strange days...Thu Oct 03 1991 18:5226
The only reason I would Forbid() or Disable() would be for their intended
purposes - to access some critical piece of data, etc.

I don't think "jerkiness" should be a factor, not with the good timing
granularity provided by the timer device. I expect that _most_ tasks will
spend more time idle than active, which should reduce jerkiness and allow
easy multi-tasking with other processes.

I'm now thinking about a task that can function as the graphics 
"engine" for the entire game.  It would take/coordinate graphics requests,
and then handle them appropriately "Move ship to X,Y", "Change ship obj to
Z" , etc.  It would either update the screen as messages came in - or
it could sit idle for a time period and then service all the messages,
double buffer the entire display, and then Wait() again.  This would also
put all the graphic operations into a single task - big benefit for 
migratability.

Clearly, I have to do some more thinking and a decent amount of prototyping
to have a better feel for how all this will fit together.

I am intending to layer a 'pthread' interface on top of the Amiga Task
interface.  Mainly to provide a somewhat migratable path, and to consolidate
functionality.  I hate to build a "perfect" world, but much of the 'pthread'
interface can be accomplished with low overhead macros, and routines.

Steve  
5090.10BAGELS::BRANNONDave BrannonFri Oct 04 1991 13:5011
    re:.0  FSM driven game?  What is FSM?
    
    Did you ever see "Star Raiders" on the Atari 8bit systems?  I'd love
    to see something like that for the Amiga.  For starters, you'd need
    a custom screen with a 3d starfield to fly thru and various things to
    shoot at that blow up real good :-)
    
    Then add the option for them to shoot back and maneuver.  And a limit
    on how many of them can attack you at the same time.
    
    Dave
5090.11pthreadss..TENAYA::MWMFri Oct 04 1991 15:297
I agree with you about pthreads being something that could be done
with relatively low overhead. I've looked at it, but never found time
to *do* anything about it.

Once again, that's something I'd be very interested in seeing.

	<mike
5090.12Problems with RemTask()?SMAUG::SPODARYKFor three strange days...Sat Oct 05 1991 18:3438
    re: .10 (What is FSM?)
    
    Finite State Machine
    
    (Generic Description)
    It's a method to simply describe a series of inputs, their 
    cooresponding actions, and the next state.  It's a way to 
    automate a set of actions, and it's used extensively in many 
    applications (communications protocols, parsers, etc).
    
    - new question -
    
    Does anyone have a WORKING example of using AddTask() and RemTask()?
    I've started writing the pthread code, and it works great using
    CreateTask/DeleteTask().  However, I need some more flexibility
    around task creation, and am trying to use Add/RemTask().
    
    The AddTask() works great, but the RemTask() crashes on the first 
    call.  I've followed the RKM and Peck's example, with no luck.
    
    Essentially, I'm trying:
    
    Forbid();		/* no impact on crashing - recommended by Peck */
    RemTask(task);
    Permit();		/* RemTask should Permit(), again no impact */
    FreeMem(task->tc_SPLower, stacksize);
    FreeMem(task, sizeof(struct Task));
    
    FF20 and FF79 have good Create/Delete examples, but no Add/RemTask.
    I'm a little confused about who/how memory should be cleaned up.
    It doesn't appear that a task can cleanup it's own memory, because
    it should stop running after it removes itself - ie. RemTask(0);
    
    Of course, memory cleanup isn't a problem - since I haven't even
    gotten that far yet!
    
    Steve
                        
5090.13prototype it as 'extern'?SMAUG::SPODARYKFor three strange days...Sat Oct 05 1991 20:1810
    Well, apparently the strange behavior was occuring with RemTask()
    because I hadn't declared it as 'extern'.  It didn't affect any
    of the other exec routines, so I'm still confused.
    
    Examples would be appreciated, but they're not critical.  I'd also
    be interested in a method to pass an argument to a task.  I guess
    that I could setup the stack/stack pointer appropriately, but I'm
    not sure the right way to do that.
    
    Steve
5090.14WHAMMY::spodarykFor three strange days...Tue Oct 15 1991 16:2524
My pthreads (POSIX 1003.4a Draft 4) implementation is coming along 
really well.  It's tough making progress only working on it at night,
and weekends, but it's almost done.

Still need to:

- implement several simple routines around condition/mutex attributes, and
  synch/asynch cancel-ability  
- implement a stdio 'daemon' to allow threads to perform "stdio" I/O
- do some performance testing and run-time analysis to check overhead/
  performance of creation/cacheing, etc.
- write a short usage, restrictions, etc, doc.

When I'm completely done I plan to release the whole thing, but if anyone
wanted an object library to play around with, I could do that right away.
All the functions around creation/deletion, condition signalling, mutex
handling, etc, are done.

It would really be nice to have the other POSIX interfaces on the
Amiga, as well as a 'socket' (or better yet, XTI) interface layered on 
MsgPorts, DECnet and/or TCP.  Any takers?   

Steve