• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.

SMurf7

Members
  • Content count

    42
  • Joined

  • Last visited

Community Reputation

122 Neutral

About SMurf7

  • Rank
    Member

Personal Information

  • Location
    UK
  1. Hello, I'm working on creating a sound engine based on OpenAL which will play both sound effects and music. The music can either be a straightforward Ogg Vorbis file or a sort of Amiga-style module (details yet to be defined). I'm doing this to allow for easier control of dynamic music in-game and because I want to encourage end users to tinker with the assets (be they graphics or music). For the music, either samples can be provided or an internal wave generator (sine, square, triangle) can be used for channel instruments. This would facilitate retro chiptunes without storing (in some cases) megabytes of MP3s. I'll admit I'm a newcomer to music programming in general, I can play Vorbis files but I currently shove the entire decompressed file into memory for playback(!). Streaming is my ultimate objective but I'm having trouble understanding how I can update something that is playing (buffers are tricky ). To start off, I have created a simple sequencer that renders individual seconds of musical notes as sine wave tones, plays them and waits until playback is finished before continuing the loop. This results in stuttery stutteriness, but again I don't know how best to handle buffering so that I can make changes to what is being played. The notes are for now stored in a simple (key, duration) format, with key indexing into an array of 84 frequencies corresponding to C1-B7 in semitone increments. Below is what I've done so far, with a hard-coded two-channel tune until I've worked out a file format. See if you can recognize it. Can anyone help with this or give me pointers on how best to achieve my stated objectives? [code]//C1 = dKeys[0] //C2 = dKeys[12] //C3 = dKeys[24] //C4 = dKeys[36] //C5 = dKeys[48] //C6 = dKeys[60] //C7 = dKeys[72] #include <math.h> #include <stdio.h> #include <stdlib.h> #include <al\al.h> #include <al\alc.h> typedef struct { char cIndex; // -1 = pause, otherwise index into dKeys unsigned char ucDuration; // measured in eighths of a second (max 15) } t_note; typedef struct { unsigned int uiFreq; // sampling rate? unsigned long ulLength; // length *in bytes* short pBuffer[1]; } t_sound; typedef struct { int fFlags; /* First four bits:- 0 = off, 1 = sine, 2 = square, 3 = triangle, 4 = sample next two bits:- 8 = decay, 16 = sustain, 24 = release */ t_note *pNote; // current note to play unsigned short usAttack; // attack duration (samples) unsigned short usDecay; // decay duration (sample) unsigned char ucSustain; // sustain volume (divided by 128) unsigned short usRelease; // release duration (samples) t_sound *pSound; // sound buffer unsigned int uiPos; // current position in buffer (samples) unsigned short usVolume; // volume of channel (max 32767) } t_channel; #define NUMCHANNELS 2 const double c_TWOPI = 2 * 3.1415926535897931; const double c_SEMITONE = 1.059463094359; // approx. twelfth root of 2 // Render note into channel buffer as per channel parameters void render_note(t_channel *pChannel, double *pdKeys) { unsigned int ui, uiDuration, uiStatePos; unsigned short usAmplitude; uiDuration = (pChannel->pNote->ucDuration & 15) * 6000; if (pChannel->uiPos + uiDuration > pChannel->pSound->uiFreq) uiDuration = pChannel->pSound->uiFreq - pChannel->uiPos; if (pChannel->pNote->cIndex == -1) { memset(&pChannel->pSound->pBuffer[pChannel->uiPos], 0, uiDuration * 2); pChannel->uiPos += uiDuration; } else { uiStatePos = 0; usAmplitude = 0; for (ui=0;ui<uiDuration;ui++) { if ((pChannel->fFlags & 24) == 0) // attack { if (ui < pChannel->usAttack) usAmplitude += pChannel->usVolume / pChannel->usAttack; else { uiStatePos = ui; pChannel->fFlags |= 8; } } if ((pChannel->fFlags & 24) == 8) // decay { if (ui - uiStatePos < pChannel->usDecay) usAmplitude -= (pChannel->usVolume - (pChannel->ucSustain * 128)) / pChannel->usDecay; else { uiStatePos = ui; pChannel->fFlags = (pChannel->fFlags & ~8) | 16; } } if ((pChannel->fFlags & 24) == 16) // sustain { if (uiDuration - pChannel->usRelease < ui) { uiStatePos = ui; pChannel->fFlags |= 8; } } if ((pChannel->fFlags & 24) == 24) // release { if (ui- uiStatePos < pChannel->usRelease) usAmplitude -= (pChannel->ucSustain * 128) / pChannel->usDecay; else usAmplitude = 0; } if (usAmplitude == 0) pChannel->pSound->pBuffer[pChannel->uiPos++] = 0; else { if ((pChannel->fFlags & 3) == 1) pChannel->pSound->pBuffer[pChannel->uiPos++] = (short)(sin(ui * pdKeys[pChannel->pNote->cIndex]) * usAmplitude); else if ((pChannel->fFlags & 3) == 2) pChannel->pSound->pBuffer[pChannel->uiPos++] = ((sin(ui * pdKeys[pChannel->pNote->cIndex]) >= 0) ? 1 : -1) * usAmplitude; } } } pChannel->pNote->ucDuration -= uiDuration / 6000; if (pChannel->pNote->ucDuration == 0) pChannel->pNote = NULL; } // initialise channel members int init_channels(unsigned char nChannels, t_channel *pChannels) { unsigned short us; for (us=0;us<nChannels;us++) { pChannels[us].fFlags = 1; pChannels[us].pNote = NULL; pChannels[us].usVolume = 16384; pChannels[us].usAttack = 480; pChannels[us].usDecay = 480; pChannels[us].ucSustain = 128; pChannels[us].usRelease = 480; pChannels[us].pSound = malloc(sizeof(*pChannels[us].pSound) + (47999 * sizeof(short))); if (!pChannels[us].pSound) return -1; pChannels[us].pSound->uiFreq = 48000; pChannels[us].pSound->ulLength = 96000; } return 0; } int main(int argc, char **argv) { double dKeys[84]; unsigned char uc; unsigned int ui, ui2; ALCcontext *alcContext; ALCdevice *alcDevice; ALint aliState; ALuint aluBuffIDs[NUMCHANNELS], aluSrcIDs[NUMCHANNELS]; t_channel channels[NUMCHANNELS]; t_note NotesCh1[39] = {{52, 2}, {52, 2}, {-1, 1}, {52, 2}, {-1, 1}, {48, 2}, {52, 2}, {-1, 1}, {55, 2}, {-1, 6}, {44, 2}, {-1, 6}, {48, 2}, {-1, 4}, {44, 2}, {-1, 4}, {41, 2}, {-1, 4}, {45, 2}, {-1, 2}, {47, 2}, {-1, 2}, {46, 2}, {45, 2}, {-1, 2}, {43, 4}, {52, 2}, {55, 2}, {57, 2}, {-1, 2}, {53, 2}, {55, 2}, {-1, 2}, {52, 2}, {-1, 2}, {48, 2}, {50, 2}, {47, 2}, {-1, 4}}; t_note NotesCh2[37] = {{30, 2}, {29, 2}, {-1, 1}, {29, 2}, {-1, 1}, {30, 2}, {29, 2}, {-1, 1}, {35, 2}, {-1, 14}, {40, 2}, {-1, 4}, {36, 2}, {-1, 4}, {31, 2}, {-1, 4}, {36, 2}, {-1, 2}, {38, 2}, {-1, 2}, {37, 2}, {36, 2}, {-1, 2}, {36, 4}, {43, 2}, {47, 2}, {48, 2}, {-1, 2}, {45, 2}, {47, 2}, {-1, 2}, {45, 2}, {-1, 2}, {40, 2}, {41, 2}, {38, 2}, {-1, 4}}; // initialise A440 dKeys[45] = (c_TWOPI * 440) / 48000; for (ui=44;ui>0;ui--) dKeys[ui] = dKeys[ui + 1] / c_SEMITONE; dKeys[0] = dKeys[1] / c_SEMITONE; for (ui=46;ui<84;ui++) dKeys[ui] = dKeys[ui - 1] * c_SEMITONE; alcDevice = alcOpenDevice(NULL); if (!alcDevice) return -1; alcContext = alcCreateContext(alcDevice, NULL); if (!alcContext) return -1; alcMakeContextCurrent(alcContext); alGenSources(NUMCHANNELS, aluSrcIDs); if (alGetError() != AL_NO_ERROR) { alcMakeContextCurrent(NULL); alcDestroyContext(alcContext); alcCloseDevice(alcDevice); return -1; } alGenBuffers(NUMCHANNELS, aluBuffIDs); if (alGetError() != AL_NO_ERROR) { alDeleteSources(NUMCHANNELS, aluSrcIDs); alcMakeContextCurrent(NULL); alcDestroyContext(alcContext); alcCloseDevice(alcDevice); return -1; } if (init_channels(NUMCHANNELS, channels) == -1) { alDeleteBuffers(NUMCHANNELS, aluBuffIDs); alDeleteSources(NUMCHANNELS, aluSrcIDs); alcMakeContextCurrent(NULL); alcDestroyContext(alcContext); alcCloseDevice(alcDevice); return -1; } ui = 0; ui2 = 0; while (ui < 39 && ui2 < 37) { for (uc=0;uc<NUMCHANNELS;uc++) { channels[uc].uiPos = 0; while (channels[uc].uiPos < channels[uc].pSound->uiFreq) { if (!channels[uc].pNote) { if (uc == 0) { if (ui == 39) break; else channels[uc].pNote = &NotesCh1[ui++]; } else { if (ui2 == 37) break; else channels[uc].pNote = &NotesCh2[ui2++]; } channels[uc].fFlags &= ~24; } render_note(&channels[uc], dKeys); } alBufferData(aluBuffIDs[uc], AL_FORMAT_MONO16, channels[uc].pSound->pBuffer, channels[uc].uiPos * 2, channels[uc].pSound->uiFreq); alSourcei(aluSrcIDs[uc], AL_BUFFER, aluBuffIDs[uc]); } alSourcePlayv(NUMCHANNELS, aluSrcIDs); do { alGetSourcei(aluSrcIDs[0], AL_SOURCE_STATE, &aliState); } while (aliState == AL_PLAYING); for (uc=0;uc<NUMCHANNELS;uc++) alSourcei(aluSrcIDs[uc], AL_BUFFER, 0); } for (ui=0;ui<NUMCHANNELS;ui++) free(channels[ui].pSound); alDeleteBuffers(NUMCHANNELS, aluBuffIDs); alDeleteSources(NUMCHANNELS, aluSrcIDs); alcMakeContextCurrent(NULL); alcDestroyContext(alcContext); alcCloseDevice(alcDevice); return 0; }[/code]
  2. JohnBolton: Yeah, I've seen y += v * t around before, it just seems to make the object fall really slowly (t = 0.02 or 1/60) and then when it hits something it appears about 60 pixels above it and doesn't move. [headshake] Unfortunately I can't draw on fractions of pixels so I don't see what benefit making x/y floating point would give. EDIT: I owe you an apology. After storing a separate double of y for use in these calculations and fixing some collision code it now works! Using y += v * t is still quite slow though. StealthNinja: Gravity is added every frame, even if there's a collision. I need the velocity to be reduced and inverted rather than set to 0 to simulate a bounce. [Edited by - SMurf7 on November 4, 2006 6:29:38 PM]
  3. Hello, I'm trying to simulate an object vertically falling with gravity and bouncing against another object, with no horizontal forces involved. Currently I have the following being executed every cycle (60 Hz):- if (tt->dVelocity || !DetectRect(me->parent, me, me->x, me->y + 1, me->w, me->h)) { tt->dVelocity += GRAVITY * 0.02; if (tt->dVelocity > 0) me->y += (tt->dVelocity - (int)tt->dVelocity >= 0.5) ? (int)tt->dVelocity + 1 : (int)tt->dVelocity; else me->y += ((int)tt->dVelocity - tt->dVelocity >= 0.5) ? (int)tt->dVelocity - 1 : (int)tt->dVelocity; } The code basically checks to see if double dVelocity is nonzero or there is nothing immediately beneath the object. Then it adds the acceleration due to gravity to the velocity (multiplied by 1/60th of a second) and rounds the result in either sign to increment the y position. Thn we have the code that is executed when the object hits something:- char szTemp[64]; sprintf(szTemp, "%lf -> ", tt->dVelocity); OutputDebugString(szTemp); tt->dVelocity *= 0.4; tt->dVelocity = -tt->dVelocity; sprintf(szTemp, "%lf\n", tt->dVelocity); OutputDebugString(szTemp); The velocity is reduced to 2/5 of its original value and then inverted to signify velocity in the opposite direction (up). Unfortunately it doesn't seem to work as planned. The object continues to bounce to a particular height. The results from the OutputDebugString calls are:- 7.840000 -> -3.136000 3.332000 -> -1.332800 2.979200 -> -1.191680 2.924320 -> -1.169728 2.750272 -> -1.100109 3.015891 -> -1.206356 2.713644 -> -1.085457 3.030543 -> -1.212217 2.707783 -> -1.083113 2.640887 -> -1.056355 2.863645 -> -1.145458 2.970542 -> -1.188217 2.731783 -> -1.092713 The velocity seems to oscillate over time and I don't know why. :(
  4. Archives are designed to losslessly compress files, and are thus intolerant of transmission errors or other types of corruption. Lossy file types like JPEG, MPEG, MP3, etc. however are packetized and hence reasonably tolerant of errors, allowing you to maintain some of the data in spite of broken blocks. Really though, in this modern era of high-quality digital connections, if an archive tells you it's broken, it's best re-downloaded. Thankfully the X/Y/Zmodem protocols are long dead. :D
  5. Hello, After doing lots of other little things, like isometric engines, I decided to go back to basics and make a goold ol' 2D platform game in Java. Currently my collision detection code for sprites looks like this:- if (m_dx != 0) { if (((m_dx < 0 && m_x + m_dx >= 0) && !m_maze.hittest(m_x - 1, m_y)) || ((m_dx > 0 && (m_x + WIDTH) + m_dx < 320) && !m_maze.hittest(m_x + WIDTH + 1, m_y))) { m_x += (m_dx > 0) ? 1 : -1; m_dx += (m_dx > 0) ? -1 : 1; } else m_dx = 0; } if (m_dy != 0) { if (((m_dy < 0 && m_y + m_dy >= 0) && !m_maze.hittest(m_x, m_y - 1)) || ((m_dy > 0 && (m_y + HEIGHT) + m_dy < 240) && !m_maze.hittest(m_x, m_y + HEIGHT + 1))) { m_y += (m_dy > 0) ? 1 : -1; m_dy += (m_dy > 0) ? -1 : 1; m_bJump = false; } else m_dy = 0; } else if (!m_maze.hittest(m_x, m_y + HEIGHT) && !m_maze.hittest(m_x + WIDTH, m_y + HEIGHT)) { // Nothing below, fall m_y++; m_bJump = false; } else m_bJump = true; Where:- WIDTH and HEIGHT are the physical bounding box dimensions of the sprite (Not necessary the size of the sprite's image); m_x and m_y are its current coords, m_dx and m_dy the change in the coords if required; m_bJump indicates whether this sprite is allowed to jump or not; And m_maze.hittest translates the given x and y to reference a tile in an associated maze or level in order to check if it's solid or not. This seems to work OK, but sprites can walk into solid areas while falling and sometimes can't jump in what should be jumpable areas (The tile immediately above the sprite is clear). Could anyone give me an idea how to tweak this so it works properly? [help]
  6. necromancer_df, you're an absolute star. [wink] I was gradually working towards that, had done loads of tests and written down data but was going up the wrong path (Using the modulus operator of all things! [embarrass]). The trig was staring me in the face but I was adamant that it wasn't necessary for this. Silly me...
  7. Nah, that's not it. ;) It seems to be something to do with width / height. If the result is < 2 there are at least 2 consecutive equal lines along the y axis (As the pic above shows). If the result is = 2 there are no consecutive equal lines. If the result is > 2 there are at least 2 consecutive equal lines along the x axis (e.g. 640x240) All I need to do now is work out exactly how many consecutive lines there are in either extreme. Hmm...
  8. Hello, I was wondering if anyone could help me with a bit of maths I'm struggling with. Given isometric tiles with width 32 and height 16 (Although only 15 of those 16 lines are drawn) and a buffer with a width a multiple of 32 and a height a multiple of 16, how can I determine the number of consecutive isometric lines consisting of the same number of tiles?