• 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.

Bozebo

Members
  • Content count

    123
  • Joined

  • Last visited

Community Reputation

108 Neutral

About Bozebo

  • Rank
    Member
  1. Do I need any defuzzification for my system? The magnitude of the output from the rules seems to closely represent a good new rate of change of car as it is (then I apply a sign based on which has the largest magnitude), so the whole output MF isn't really required in my system. If I am to use defuzzification, there seems to be no concrete way to select a method based on the purpose of the FIS. Bearing in mind that this is probably the last time I will use fuzzy inference systems...
  2. [quote name='staticVoid2' timestamp='1306167760' post='4814637'] also, I was meaning to ask... do many games using the client-server model perform collision detection on the client as well as the server? I had implemented it this way at first but I then tried turning off collision on the client and it seems to be working fine. [/quote] In source and unreal I believe it does movement physics/collision on both sides. The client assumes it's movements were accepted but can be "bungeed" to where the server dictates it should be (happens a lot when 'lagging'). This works flawlessly until the player touches another player or non-static geometry, then determinism can be used to improve the results in those situations - but network latency is always a problem. In games like WoW, collision is only done client side. If collision is only done server side, the client has to wait for a response before it can move - this will be horrible if the latency is not very small. [url="http://gafferongames.com/networking-for-game-programmers/what-every-programmer-needs-to-know-about-game-networking/"]this gaffer on games article is very helpful[/url] To be honest, you can probably get away with only doing collision detection on client side, unless you are releasing the game to a large audience. There are so many other ways to cheat in games that fully breaks the experience that something which seems like a huge cheat oppertunity isn't actually that big a deal - the gameplay is already broken if somebody uses a wallhack or aimbot in a fps, being able to fly around in noclip due to client-side only physics just makes it more obvious. Server-side collision detection is required when there are moving collidable objects.
  3. I have something that works now: [source lang="cpp"] #include <iostream> #include <math.h> //for keyboard input #include "conio.h" //for Sleep() #include "Windows.h" using namespace std; //global for Euler's/Napier's constant double e = 2.718281828459045235360287471352; //sigmodally shaped membership function double sigmf(double x, double a, double c){ return 1 / (1 + pow(e,-a * (x - c))); } //class to encapsulate line movement and basic kinematics class Line{ float x; float xMax; float xSpeed; float xSpeedMax; float friction; float accel; public: Line(float sX, float sXMax, float sFriction, float sXSpeedMax, float sAccel){ x = sX; xMax = sXMax; friction = sFriction; xSpeedMax = sXSpeedMax; accel = sAccel; xSpeed = 0; } void update(){ //if a key has been pressed if(_kbhit() != 0){ switch(_getch()){ // A or a case 97: case 65: xSpeed -= accel; //apply motion down the axis if(xSpeed < -xSpeedMax) xSpeed = -xSpeedMax; //cap the speed break; // D or d case 100: case 68: xSpeed += accel; //apply motion up the axis if(xSpeed > xSpeedMax) xSpeed = xSpeedMax; //cap the speed break; } } if(xSpeed > 0){ //if moving xSpeed -= friction; //apply friction if(xSpeed > 0){ //if still moving x += xSpeed; //move if(x > xMax){ //don't go out of bounds x = xMax; xSpeed = 0; } } else { xSpeed = 0; //don't let friction make it move the other way return; } } else if(xSpeed < 0){ //if moving xSpeed += friction; //apply friction if(xSpeed < 0){ //if still moving x += xSpeed; //move if(x < 0){ //don't go out of bounds x = 0; xSpeed = 0; } } else { xSpeed = 0; //don't let friction make it move the other way return; } } } void draw(){ int i; //pad with spaces until max x marker co-ord for(i = 0;i < xMax;i ++){ cout << " "; } cout << "V\n"; //draw the max x co-ord marker //pad with spaces until x co-ord for(i = 0;i < x;i ++){ cout << " "; } cout << "|\n"; //draw the line } float getX(){ return x; } float getXMax(){ return xMax; } }; //fuzzy inference system class class FuzzySystem{ //ranges of membership functions double distRange, currentSteerRange, outRange, //results of membership functions distMfLeft, distMfRight, steerMfLeft, steerMfRight; //distance input membership functions double distInputMf_Left(double dist){ double sigmfResult = sigmf(dist,-0.19,-18.23); return sigmfResult; } double distInputMf_Right(double dist){ double sigmfResult = sigmf(dist,0.19,18.23); return sigmfResult; } //rate of change input membership functions double currentSteerInputMf_Left(double currentSteer){ double sigmfResult = sigmf(currentSteer,1.02,5.228); return sigmfResult; } double currentSteerInputMf_Right(double currentSteer){ double sigmfResult = sigmf(currentSteer,-1.02,-5.228); return sigmfResult; } //rate of change output membership functions double steerOutputMf(double steerOutput){ return steerOutput * 10; double sigmfResult = sigmf(steerOutput,-0.1,0.028); return sigmfResult; } //calculates the results of input membership functions void computeInputs(double dist, double steer){ //evaluate distance input membership functions distMfLeft = distInputMf_Left(dist); printf("distMf_Left value: %.4f\n",distMfLeft); distMfRight = distInputMf_Right(dist); printf("distMf_Right value: %.4f\n",distMfRight); //evaluate currentSteer input membership functions steerMfLeft = currentSteerInputMf_Left(steer); printf("steerMfLeft value: %.4f\n",steerMfLeft); steerMfRight = currentSteerInputMf_Right(steer); printf("steerMfRight value: %.4f\n",steerMfRight); } //calculates the output from the system based on input results float output(){ /* //if dist and current steer are "right" (rule) if(oDistResult < 0.01){ //find a new output double newSteer = sigmf(oDistResult,1.02,5.228); printf("rule: 'right'\nFIS output (newSteer): %.4f\n", newSteer); return static_cast<float>(newSteer); //if dist and current steer are "left" (rule) } else if(oDistResult > 0.01){ //find a new output double newSteer = sigmf(oDistResult,1.02,5.228); printf("rule: 'left'\nFIS output (newSteer): %.4f\n", newSteer); return static_cast<float>(-newSteer); } else { printf("rule: no rule applies\n\n"); return 0.0f; //no speed, close enough to the line } */ //rules /* //rule 1 //distance is right and currentSteer is right //take the largest double rule1Result; rule1Result = (distMfRight > steerMfRight)? distMfRight: steerMfRight; printf("rule 1 outcome: %.4f\n",rule1Result); //rule 2 //distance is left and currentSteer is left //take the largest double rule2Result; rule2Result = (distMfLeft > steerMfLeft)? distMfLeft: steerMfLeft; printf("rule 2 outcome: %.4f\n",rule2Result); double steerResult; //which rule was more prominent if(rule1Result > rule2Result){ steerResult = rule1Result*10; } else { steerResult = -rule2Result*10; } */ //printf("new speed: %.4f\n",steerResult); //return steerResult; return 0; } public: //constructor, sets up the range for inputs and outputs FuzzySystem(double sDistRange = 60, double sCurrentSteerRange = 10, double sOutRange = 10){ outRange = sOutRange; distRange = sDistRange; currentSteerRange = sCurrentSteerRange; } //returns a new speed for the car based on the outcome of fuzzy logic float resolve(double dist, double currentSteer){ computeInputs(dist, currentSteer); //holds the input results based on the applied rules //double inputResultDistance, inputResultCurrentSteer; /* if (distance is right) and NOT(currentSteer is left) then (steer is left) if (distance is left) and NOT(currentSteer is right) then (steer is right) */ double steerLeft, steerRight; //if (distance is right) and NOT(currentSteer is left) then (steer is left) steerLeft = (distMfRight > 1-steerMfLeft)? steerMfLeft: distMfRight; //if (distance is left) and NOT(currentSteer is right) then (steer is right) steerRight = (distMfLeft > 1-steerMfRight)? steerMfRight: distMfLeft; printf("steerLeft: %.4f\n" "steerRight: %.4f\n", steerLeft, steerRight); printf("steerOutputMf(steerLeft): %.4f\n",steerOutputMf(steerLeft)); printf("steerOutputMf(steerRight): %.4f\n",steerOutputMf(steerRight)); //output value double out; //which member function has the greatest magnitude if(fabs(steerLeft) > fabs(steerRight)){ out = -steerOutputMf(steerLeft); } else { out = steerOutputMf(steerRight); } printf("out: %.4f\n",out); //float steerOut = // float out = output(dist, currentSteer); return out; //return 0; } float resolve(float dist, float currentSteer){ return resolve(static_cast<double>(dist),static_cast<double>(currentSteer)); } }; //class to encapsulate the car and it's associated AI class CarAI{ Line* line; //maintain a pointer to the line FuzzySystem* fuzzy; //pointer to a fuzzy inference system float x, xLast, xSpeed; //returns the distance to the line float distToLine(){ return x - line->getX(); } //returns the rate of change of the car's x co-ordinate float xChange(){ return x - xLast; } public: CarAI(Line* sLine){ fuzzy = new FuzzySystem; line = sLine; x = 30.0f; xSpeed = 0; } //called each frame to assess car AI and apply motion void update(){ //have the fuzzy inference system control the x speed xSpeed = fuzzy->resolve(distToLine(),xChange()); //cap the speed /* if(xSpeed < -10) xSpeed = -10; if(xSpeed > 10) xSpeed = 10; */ //remember previous x co-ord xLast = x; //apply motion x += xSpeed; //clamp into range if(x < 0) x = 0; if(x > line->getXMax()) x = line->getXMax(); } void draw(){ int i; //pad with spaces until x co-ord for(i = 0;i < x;i ++){ cout << " "; } cout << "#\n"; //draw the car } float getX(){ return x; } }; int main(){ //introduction message int dots = 1; //loop while there is no keyboard input while(_kbhit() == 0){ if(dots == 1){ //introduction message cout << "AI For Games Development - coursework\n"; cout << "0801109 - Philip Robinson\n"; cout << "Racing Line FIS test application\n\n"; cout << "A and D allow the racing line (|) to be moved left and right.\n"; cout << "V marks the maximum x co-ordinate of the racing line and the " "car.\n"; cout << "The car is denoted by a # character.\n\n"; cout << "Press any key to continue"; } cout << "."; dots ++; Sleep(600); if(dots > 3){ dots = 1; //clear the screen system("cls"); } } //make the Line object Line line(11,60,0.16f,3.0f,0.32f); //make the CarAI object CarAI car(&line); //is the update loop to keep running or not bool run = true; //sleep time in ms each frame int sleepTime = 30; //frame counter long frame = 0; //enter the main loop while(run){ //clear the screen system("cls"); //increment the frame counter frame ++; //update the racing line line.update(); //update the car car.update(); //show the frame count cout << "frame: " << frame << endl; cout << "line x: " << line.getX() << endl; cout << "car x: " << car.getX() << endl; //draw the line line.draw(); //draw the car car.draw(); //limit the frame rate Sleep(sleepTime); } //clear the screen system("cls"); //write closing message cout << "closing app\n"; //sleep Sleep(1000); //end the process return 0; } [/source] Only problem is it jitters back and forth when it gets very close to the line, but I can edit my membership functions to fix that. This part confused me: [source lang="cpp"] //if (distance is right) and NOT(currentSteer is left) then (steer is left) steerLeft = (distMfRight > 1-steerMfLeft)? steerMfLeft: distMfRight; //if (distance is left) and NOT(currentSteer is right) then (steer is right) steerRight = (distMfLeft > 1-steerMfRight)? steerMfRight: distMfLeft; [/source]
  4. [quote name='IADaveMark' timestamp='1306461245' post='4816270'] Sigh. I wish I understood the fascination with fuzzy logic when a simple set of response curves can do wonders. Adding in the fuzzy sets is a whole unnecessary layer. [/quote] I agree. Especially after wrestling with this, trying to get it to work. FIS could be useful on large projects however, where different people are providing rules to be used within somebody else's application and the level of control is required, but it doesn't really help if the programmed FIS layer isn't pluggable - which mine isn't. It seems a bit too "catch-all" to be effective.
  5. Hi, I have a piece of coursework set to make an implementation of a fuzzy inference system in C++ to control a "car" that moves in the direction towards a "line" along one axis. I feel I have a fairly good grasp of the whole purpose and reason for fuzzy logic, particularly for game AI, but I get a bit confused when it comes down to actually implementing it. Firstly, here is a screenshot of my fuzzy inference system in matlab: [img]http://bozebo.com/images/screen.png[/img] As you can see, I have 2 inputs (each with 2 membership functions), 2 rules and 1 output. I understand the inputs well, but I don't quite see how the output values properly tie in via the rules to give a sensible output. My system should assess the current motion of the car and the distance between the car and the line to output a new car motion (change along the single axis in units per frame). I don't think my output is doing anything useful, but I don't understand what an output actually 'does' based on the rules. Considering rules, what I thought I should be looking for was a way to assess greater or less than, but the only valid options are equal to or not equal to an input's membership function. My application follows this structure: [code] //define membership functions for inputs (sigmf curves for rate of change of car and distance from line target) //called every frame, 30 frames per second update(){ //evaluate input membership function results //evaluate rules based on input results //set new rate of change of car based on output membership function } [/code] The part I don't understand is how an output membership function has any application towards evaluating a rate of change. My output has 2 membership functions, and my rules should dictate which one is applied. But what are the inputs to my output membership functions? I can't seem to find a good explanation online or in my course notes, I am probably very close to getting this to work nicely but my misunderstanding is probably making it seem more complicated than it should be. Here is the full source (it isn't pluggable yet, while I test it): [source lang=cpp] #include <iostream> #include <math.h> //for keyboard input #include "conio.h" //for Sleep() #include "Windows.h" using namespace std; //global for Euler's/Napier's constant double e = 2.718281828459045235360287471352; //sigmodally shaped membership function double sigmf(double x, double a, double c){ return 1 / (1 + pow(e,-a * (x - c))); } //class to encapsulate line movement and basic kinematics class Line{ float x; float xMax; float xSpeed; float xSpeedMax; float friction; float accel; public: Line(float sX, float sXMax, float sFriction, float sXSpeedMax, float sAccel){ x = sX; xMax = sXMax; friction = sFriction; xSpeedMax = sXSpeedMax; accel = sAccel; xSpeed = 0; } void update(){ //if a key has been pressed if(_kbhit() != 0){ switch(_getch()){ // A or a case 97: case 65: xSpeed -= accel; //apply motion down the axis if(xSpeed < -xSpeedMax) xSpeed = -xSpeedMax; //cap the speed break; // D or d case 100: case 68: xSpeed += accel; //apply motion up the axis if(xSpeed > xSpeedMax) xSpeed = xSpeedMax; //cap the speed break; } } if(xSpeed > 0){ //if moving xSpeed -= friction; //apply friction if(xSpeed > 0){ //if still moving x += xSpeed; //move if(x > xMax){ //don't go out of bounds x = xMax; xSpeed = 0; } } else { xSpeed = 0; //don't let friction make it move the other way return; } } else if(xSpeed < 0){ //if moving xSpeed += friction; //apply friction if(xSpeed < 0){ //if still moving x += xSpeed; //move if(x < 0){ //don't go out of bounds x = 0; xSpeed = 0; } } else { xSpeed = 0; //don't let friction make it move the other way return; } } } void draw(){ int i; //pad with spaces until max x marker co-ord for(i = 0;i < xMax;i ++){ cout << " "; } cout << "V\n"; //draw the max x co-ord marker //pad with spaces until x co-ord for(i = 0;i < x;i ++){ cout << " "; } cout << "|\n"; //draw the line } float getX(){ return x; } float getXMax(){ return xMax; } }; //semi-pluggable fuzzy inference system class class FuzzySystem{ double distRange, currentSteerRange; //distance input evaluation double distInput(double dist){ double sigmfResult = sigmf(dist,-0.19,-28.23) * distRange; if(dist > 0) return sigmfResult; return -sigmfResult; } double distInput(float dist){ return distInput(static_cast<double>(dist)); } //rate of change input evaluation double currentSteerInput(double currentSteer){ double sigmfResult = sigmf(currentSteer,-1.02,-5.228) * currentSteerRange; if(currentSteer > 0) return sigmfResult; return -sigmfResult; } double currentSteerInput(float dist){ return currentSteerInput(static_cast<double>(dist)); } //calculates the output from the system based on input results float output(double oDistResult, double oCurrentSteerResult){ //if dist and current steer are "right" (rule) if(oDistResult < 0){ //find a new output double newSteer = sigmf(oDistResult,1.02,5.228)*10; //cout << "newSteer: " << newSteer << endl; printf("'right'\nnewSteer: %.4f\n",newSteer); return static_cast<float>(newSteer); //if dist and current steer are "left" (rule) } else if(oDistResult > 0){ //find a new output double newSteer = sigmf(oDistResult,1.02,5.228)*10; //cout << "newSteer: " << newSteer << endl; printf("'left'\nnewSteer: %.4f\n",newSteer); return static_cast<float>(-newSteer); } else return 0.0f; //no speed, close enough to the line } public: //constructor, sets up the range for inputs FuzzySystem(double sDistRange = 60, double sCurrentSteerRange = 10){ distRange = sDistRange; currentSteerRange = sCurrentSteerRange; } //returns a new speed for the car based on the outcome of fuzzy logic float resolve(double dist, double currentSteer){ cout << dist << endl; cout << currentSteer << "\n-------------------\n"; double distResult = distInput(dist); double currentSteerResult = currentSteerInput(currentSteer); cout << "distResult: " << distResult << endl << "currentSteerResult: " << currentSteerResult << "\n-------------------\n"; float out = output(distResult, currentSteerResult); return out; } float resolve(float dist, float currentSteer){ return resolve(static_cast<double>(dist),static_cast<double>(currentSteer)); } }; //class to encapsulate the car and it's associated AI class CarAI{ Line* line; //maintain a pointer to the line FuzzySystem* fuzzy; float x, xLast, xSpeed; //returns the distance to the line float distToLine(){ return x - line->getX(); } //returns the rate of change of the car's x co-ordinate float xChange(){ return x - xLast; } public: CarAI(Line* sLine){ fuzzy = new FuzzySystem; line = sLine; x = line->getX() + 2.327f; xSpeed = 0; } //called each frame to assess car AI and apply motion void update(){ //have the fuzzy inference system control the x speed xSpeed = fuzzy->resolve(distToLine(),xChange()); //cap the speed if(xSpeed < -10) xSpeed = -10; if(xSpeed > 10) xSpeed = 10; //remember previous x co-ord xLast = x; //apply motion x += xSpeed; //clamp into range if(x < 0) x = 0; if(x > line->getXMax()) x = line->getXMax(); } void draw(){ int i; //pad with spaces until x co-ord for(i = 0;i < x;i ++){ cout << " "; } cout << "#\n"; //draw the car } }; int main(){ //introduction message int dots = 1; //loop while there is no keyboard input while(_kbhit() == 0){ if(dots == 1){ //introduction message cout << "AI For Games Development - coursework\n"; cout << "0801109 - Philip Robinson\n"; cout << "Racing Line FIS test application\n\n"; cout << "A and D allow the racing line (|) to be moved left and right.\n"; cout << "V marks the maximum x co-ordinate of the racing line and the " "car.\n"; cout << "The car is denoted by a # character.\n\n"; cout << "Press any key to continue"; } cout << "."; dots ++; Sleep(600); if(dots > 3){ dots = 1; //clear the screen system("cls"); } } //make the Line object Line line(11,60,0.16f,3.0f,0.32f); //make the CarAI object CarAI car(&line); //is the update loop to keep running or not bool run = true; //sleep time in ms each frame int sleepTime = 30; //frame counter long frame = 0; //enter the main loop while(run){ //clear the screen system("cls"); //increment the frame counter frame ++; //update the racing line line.update(); //update the car car.update(); //show the frame count cout << "frame: " << frame << endl; cout << "line x: " << line.getX() << endl; //draw the line line.draw(); //draw the car car.draw(); //limit the frame rate Sleep(sleepTime); } //clear the screen system("cls"); //write closing message cout << "closing app\n"; //sleep Sleep(1000); //end the process return 0; } [/source] Can anybody direct me to further reading on the topic, or clarify how it all goes together for me? I understand that this post is a bit ambiguous, but that only reflects my own confusion on this topic; feel free to probe me for anything else you need to know to help me. I want to get this completed soon. Thanks in advance for any help.
  6. [quote name='rip-off' timestamp='1305210951' post='4809794'] Is the ribMoverController object (the one you call insertMover() on) valid? [/quote] No it wasn't! Thanks. I forgot to even spawn an instance of ribMoverController in the pointer I had declared for it and was using to access it. That was a silly mistake.
  7. I have used maps in this way before without any issues, but now I am encountering a segmentation fault that I can't find a solution to. I have 2 classes, and one of them holds a map of pointers to objects in the other class, with ints as keys (I tried unsigned shorts before then reverted to ints trying to fix it, I will stick with ints for now) [source lang=cpp] #include <queue> #include <map> struct moverLocation{ float x,y; unsigned long tick; unsigned int msAfter; }; class ribMover{ int id; std::queue<moverLocation> locations; public: ribMover(int setId); void addLocation(float sX, float sY, unsigned long tick, unsigned int msAfter){ moverLocation newLocation; newLocation.x = sX; newLocation.y = sY; newLocation.tick = tick; newLocation.msAfter = msAfter; locations.push(newLocation); } }; class ribMoverController{ std::map<int,ribMover*> movers; public: //creates a new mover void newMover(int moverId){ std::pair<int,ribMover*> mapPair(moverId,new ribMover(moverId)); //make a pair movers.insert(mapPair); //insert the pair into the map fprintf(logFile,"new mover created with id %d\n",moverId); } //deletes a mover void deleteMover(int moverId){ movers.erase(moverId); //remove the mover fprintf(logFile,"mover with id %d deleted\n",moverId); } }; [/source] It crashes on the line: movers.insert(mapPair); Why? I have used maps like this in the past without any problems at all. Also, I wasn't originally storing pointers to objects in the map, but when that didn't work I switched to pointers incase that would help somehow. I've checked my code many times. The only difference between it and another instance of maps I programmed recently is that it uses ints whereas I was using SOCKET types (also an int I believe).
  8. I am only running this on x86, I should have mentioned that. I used ntohl etc. initially because I thought I had to (not understanding that most of the articles I read were old and acted like home machines would be using different endianness), I havn't since removed them from my code. I will try sending the float as it is without doing anything to it. edit: It works now, I am just sending the float as is. Thanks. I probably won't need to be working with networking accross platform boundaries for some time.
  9. [font="Arial Black"][size="3"][b]solved[/b][/size][/font] Hello yet again. I have a function to write a float to a buffer and a function to read a float from a buffer. It should work for positive and negative floats but It only works properly with positive floats. This code sample should explain what I mean: [code] //append a numeric value to the out buffer void addValOut(char valToAdd); void addValOut(unsigned short valToAdd); void addValOut(unsigned long valToAdd); void addValOut(long valToAdd); void addValOut(float valToAdd); //get numeric values from the in buffer char getChar(); unsigned short getUshort(); unsigned long getUlong(); long getLong(); float getFloat(); //adds bytes for a value to the out buffer - overloaded for long void ribClient::addValOut(long valToAdd){ //convert byte order to network byte order long toAdd = htonl(valToAdd); char strToAdd[4]; memcpy(strToAdd,&toAdd,4); //add to the out buffer outBuff.append(strToAdd,4); } //adds bytes for a value to the out buffer - overloaded for float, htonl is handled by addValOut(long valToAdd) void ribClient::addValOut(float valToAdd){ long convertedFloat = *reinterpret_cast<long *>(&valToAdd); addValOut(convertedFloat); } //returns an unsigned long determined from the next location in the inBuff float ribClient::getFloat(){ long floatAsLong = getLong(); float floatForm = *reinterpret_cast<float *>(&floatAsLong); return floatForm; } [/code] If I send 2 floats: 33.212 and -135.23 the outputs on the other end are: 33.2129 and -512.0000. (I presume the extra .0009 on the first one is meant to happen?) I can send everything except floats fine. I get the same result using an unsigned long or signed long to hold the float. Any ideas? I presume I am misunderstanding how floats are stored, the results of my googling/searching lead to various different threads and sites - none of which seemed consistent. edit: I tried sending 86212 and it was read as 86527.9922 small positive values seem to work though.
  10. OK. It turns out my timing was always fine, the problem was with how I was reporting the time passed. Hplus, that is how I am doing it. My pseudo code was a bit over-simplified. The error in my code is only caused by my initial recording of the baseline (because it is taken during init instead of when the first ticks tarts) - so there is/was an overall error of about 0.003 seconds. I have since edited my ticker class to incorporate that and am now using the HPET on the client too. Thanks for the help guys. I still think there will be a long term inaccuracy due to the calculation of countsPerTick (HPET frequency/tickrate) but I can make the code self detect its own inaccuracy and adjust countsPerTick +/- 1 to become inaccurate in the opposite direction and it will always remain just as accurate as the HPET on the machine in the long term. It starts off with each tick taking slightly more than 1 30th of a scond, I can make it take slightly less than 1 30th of a second after detecting it has drifted too far off accuracy in that direction and vice versa. I now have the issue of dealing with sudden delays in TCP. It can be very smooth for ages and then get a burst of data that is an extra 200-600ms late (very easy to force by sending something at maximum bandwidth over the LAN from the host machine with ftp) - which is to be expected of TCP of course. It's fine on localhost though, which is all I need to demonstrate with this - I will make something else from the ground up with a UDP system. Hmmm... now to send floats...
  11. [img]http://www.bozebo.com/images/tickTiming2.png[/img] I am not sure what I changed, but it seems to work very nicely now. Of course there is going to some inaccuracy involved with the "counts per tick" but I can either leave it as it is or incorporate some kind of self inaccuracy detection into it so that it adjusts counts-per-tick to sway the inaccuracy towards the other direction until it has drifted off by a certain amount again - and repeat in the opposite direction. As long as it is accurate according to the average over large time periods it should serve its purpose extremely well.
  12. [b][font="Arial Black"][size="3"]solved[/size][/font][/b] Hello again. The timing of my game events (mostly interp/extrap and movement tracking) rely on a steady tick rate/heartbeat. I am struggling to find a way that doesn't drift farther away from accuracy the longer the program is running for. At the moment, I am using the HPET through the Windows API functions QueryPerformanceCounter and QueryPerformanceFrequency. I have also tried a similar method using clock(). I have added code to print how many seconds (nearly exactly) that the application has been running for, I then compare this to the number of ticks passed and the time it takes for one tick. I understand that rounding issues will exist, but something odd seems to be happening. Here is a pseudo-code version of my server's tick timing: [code] query performance counter value at app start calculate counts per tick (tickrate 30, theoretical counter resolution of 200000 = 200000/30 = 6667 rounded) calculate performance counter value for when the next tick should start (current + counts per tick) set current tick to 1 set minutes passed to 0 while(running){ //do something to take up time like Sleep(1), or don't... doesn't change the outcome either way from my findings get current counter value calculate gap = current - when next tick should start if(gap >= 0){ //if a new tick is due increment the tick calculate counter value for when the next tick should start (current - gap + counts per tick) if(tickrate ticks have passed since this last resolved to true){ increment minutes passed print exact seconds passed - (current counter - starting counter - gap)/counter frequency } } } [/code] Every time a minute has passed, the printed value in seconds drifts upwards by 0.09. Which proves that the tick count doesn't accurately represent the time passed, each tick is infact taking less time than it should by a tiny bit. Here is another strange thing that happened. I originally wrote a class to calculate ticks on the client app using clock() and used the performance timer on the server. Tick signals reaching the client would be behind the ticks that the client was on (when it should have been the opposite). In an attempt to debug the server, I started making use of that class on the server too - the inaccuracy is the same as reported by my printed information - but the syncronization to the client started behaving as I was expecting in the first place (the client is always about 1 or 2 ticks behind the server). That seems quite paradoxical to me, but I won't worry about it just yet. Here is a screenshot (using clock() on the server, but the command window shows the same results as I got using the high performance event timer): [img]http://www.bozebo.com/images/tickTiming.png[/img] Green underlined text is printed based on the number of ticks passed, in the same conditional statement it prints the calculated number of seconds passed. As you can see, this drifts upwards. Essentially, I need to fix my code so that the inaccuracy doesn't keep drifting larger as more time passes. Have I done something horribly wrong with my logic, or do I need to calculate the inaccuracy in runtime and account for it? I understand that rounding errors will occur, but I can't think of a way to do it that doesn't suffer from them.
  13. [quote name='hplus0603' timestamp='1304967438' post='4808664'] If the opcode tells you whether the data is known length or not, then that layer actually has to understand what the opcodes mean. This is a high degree of coupling that's generally not very robust. If you always send the opcode and length in a known format, then that layer can give you a complete packet, without needing to know anything about what might be in that packet, or what opcodes "mean." [/quote] That makes sense. I have been struggling to find a proper way to form my messaging system into true object orientated way of working: I knew that programming a way to "get next complete packet if there is one." would be awkward, if all messages have a size it will be cleaner and simpler.
  14. The way I do this is to update a buffer whenver recv returns something (so recv is called in a loop somewhere, 10 times a second works OK for me at the moment). The first 2 bytes of the buffer are always meant to be an unsigned short representing an op-code. Each op-code relates to a command (such as login, update health, spawn zoned-in player etc). Every command has a known exact length or a variable length. If they have a variable length, the 2 bytes after the op-code describe this. so: [ushort op-code][ushort length][bytes for message data] or for a message of known length: [ushort op-code][exact number of bytes for message data] the buffer could be something like this: [op][len][arguments][op][arguments][op][arguments][op][len][arguments][op][op][len][arguments] (nothing stoping you making messages without any arguments, all that is needed is the op-code) The only way the buffer can become corrupted (ie, the first 2 bytes are not infact an op-code, but any other 2 bytes) is if there is bad programming somewhere or the packets leaving the client machine are being manupulated (so, custom client application or man in the middle etc.). Input validation should result in notification of a corrupted buffer, my applications' buffers only get corrupted if I purposely make them do so for testing the robustness of my code. And my code always detects the corrupted buffer, but sometimes there are artifacts (ie, if the first 2 bytes happen to be a [moveto] message when infact they were meant to be part of something completely different - the bytes after these 2 are then parsed as the moveto location. At the moment, my clients' input for some things is instantly trusted - so it can cause the player to teleport to an inaccessible location! Rather than the server noticing that the requested location is impossible) With this format, it can always be known how many bytes are expected for a message, so the char array buffer can be clipped one message at a time: First, decide how many bytes following the first 2 are part of the message (eg, if login is known to send an unsigned long playerID and a 32 byte md5 sum). Second, check if the buffer is at least this many bytes long Third, extract your data and trim it off the start of the buffer - the 2 bytes now at the start of the buffer should be the op-code for the next waiting message You may want to incorporate things like the max number of messages to be resolved in one go, and the max buffer size to be expected from a behaving device on the other end (if you discover your game code only leaves about 200 bytes in the server's buffer on average, cap it at 1500 or something - if a connection has more than 1500 bytes in it's buffer for any length of time, kill it) I also like to make a message that denotes how many messages from that device have been handled, so the client knows that the server is keeping up with it's message output - If you count messages out and in on both sides of the connection. One problem I find doing things this way is that it is hard to make a proper object orientated system to handle messages, I tend to resort to hard coding most messages with switch statements... messy. Complex things like spawning new players that have just logged in send the argument bytes to a deserialise method on my object. If I had a command/event system yet, it would help make this easier.
  15. [url="http://nehe.gamedev.net/"]NeHe.gamedev.net[/url] It is largely out of date now, but it is still a great starting point. I don't know if you will find "classes" as such.