Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Community Reputation

109 Neutral

About GGulati

  • Rank
  1. GGulati

    Ideas for zombie movement

    Have you heard of flocking algorithms? It creates nice behaviors for a crowd of zombies if you have them seek towards your player when the player is sighted. You can decompose zombies into mobs (aka flocks) by world position using an island algorithm. The rough pseudocode for flock creation is something like this: clear all zombie flock IDs for each zombie if zombie's flock ID is unassigned find nearby zombies with assigned flock IDs if there are such zombies set this zombie's flock ID to the nearest zombie's flock ID if no zombies are nearby create a new valid flock ID for this zombie Once in a long while (every several seconds? 30 seconds? A random value between 15 and 30 seconds?) you'd re-group the zombies into flocks so the mobs shift over time. If 5 zombies are near each other, they behave as part of a mob, as does a mob of 50 zombies. Moreover, regrouping the zombies over time allows for zombies to easily wander around the map. Of course, that is a complex solution. A simpler solution could be a messaging system. For example, when a zombie notices the player, it alerts all zombies within "hearing distance" of it. Maybe if it's night, the zombies can notice the player from further away and/or alert zombies that are further away. All zombies that become aware of the player perform this process as well. Zombies that are alerted to the player's presence start behaving in some appropriate fashion - pathfinding to the player, flocking behaviors, etc.
  2. I'll assume you're familiar with terminology such as method/function call, what a method/function is, and the concept of arguments. Well, the stack and the heap are "places" where your computer stores data. Some of this data is created and manipulated by your code (variables!), while some of the data is taken care of by the .NET runtime. For the first part, I'm going to ignore the heap - it basically doesn't exist. The stack stores function call information. The thing at the very, very bottom of the stack (in C#) is your application's entry point - the Main method. The reason the stack is called the stack is because new data is "stacked" on top of previous data. So if the only thing your Main method did is System.Console.WriteLine(), your stack would have two functions on it - Main, and on top of that, System.Console.WriteLine(). [attachment=5867:part1.png] Now, let's say you're creating a Hello World program. So your Main method looks something like System.Console.WriteLine("Hello World!"). Your stack still has the functions on it, but it also has a string on the stack - so at the bottom of the stack is the function Main, then the function System.Console.WriteLine, and at the very top, the string "Hello World!". [attachment=5868:part2.png] This also works if you use more involved functions with more arguments - at the bottom of the stack is the function Main, then the function that you called, then all of the arguments one by one. That's great, but most programs aren't just one function call inside Main, right? I mean, you declare variables and stuff. The thing about variables is that they also go on the stack - assuming you don't create any classes. Structs (including primitives such as int, float, double, string, byte, etc) are generally allocated on the stack, but if they're member variables of a class they are allocated on the heap - I'll touch on that later. There's one other thing about the stack: it grows and shrinks over time. So remember the Hello World example? When the program finishes writing text to the console, the stack will only contain the function Main - both the function System.Console.WriteLine and the string argument will have been popped off the stack. If the method you just called returned a value, that value gets added to the stack where the function call used to be. [attachment=5869:part3.png] One way of visualizing the stack is like a tower of books (or magazines or comics ). You start with one book - let's say it's Learn C# in 30 Days, or some variant thereof. You start reading it, and partway through it refers to another book (calls a function) about game programming. So you go and checkout the book from your local library. You stick a bookmark in Learn C# in 30 Days and put it on your floor. You start reading the game programming book, and partway through you find another interesting book about game AI (another function call!) and you go check that out from the library. So you take the game programming book, put a bookmark in it, and stack it on top of the Learn C# in 30 Days book. And so on. Eventually, you finish a book. So you take the topmost book off your stack of books - let's say it's the game AI one - and continue reading it. Eventually, you finish reading it. Then you get back to the game programming one, continue reading... and decide you want to learn physics (even more function calls). Back to the library! And your stack of books grows and shrinks over time, until at last you finish the last page of your Learn C# in 30 Days book (the Main method ends and your program exits). Well, that's a quick overview of how the stack works. Now, onwards to the heap! The heap is actually just a bunch of memory - that is, places where you can store data. Why do we need the heap when we have the stack? Because the stack is limited in size. In C#, the stack is (I believe) 1 megabyte per thread. By the way, that's why you get StackOverflowExceptions - there were just too many books in a pile and eventually you hit the ceiling so you couldn't pile on any more books. The heap is also limited in size, but it's much, much larger. On a computer with 2 gigabytes of RAM, the heap might be up to 1 gigabyte of memory, and if your computer had 4 gigabytes of RAM the heap might be as large as 3 gigabytes. There's one other big difference between the stack and the heap: the heap grows, while the stack's capacity doesn't change (in C#). What this means is that if you're creating a program that manages half a megabyte of data, your heap will not be that big. On the other hand, if you have a gigabyte of art and assets, your heap is going to be fairly large. And it'll grow from it's initially small size over time as you allocate more and more memory (use up more and more of the capacity) to meet your needs - at least until the .NET framework tells it that it's already used up all 3 gigabytes (or whatever). When the heap runs of out of memory, .NET creates an OutOfMemoryException. You use the heap for reference types. So that really means all classes. In the example you posted, MyInt is a class, and therefore uses the heap. What happens is that you allocate the memory necessary for the class on the heap (8 bytes of C#'s overhead and 4 bytes for the actual data) and create a 4-byte reference to an instance on the stack (if you're on a 64 bit machine, the overhead is 16 bytes aka 2 times 64 bits and the reference is 8 bytes aka 64 bits). Then, whenever you access the member data, the code is internally doing some pointer math... on the 4 byte reference on the stack. So that's where it gets confusing. You're doing pointer math on the stack, but the actual data you're manipulating is on the heap. There's quite a bit more you can learn about the stack and heap. Chiefly, speed concerns, how structs and classes behave as member variables in terms of memory and speed, the .NET garbage collector and the hardware caching of memory. Hopefully my (not-so-brief) summary of the stack and heap helped you a bit; if not, just mention what you're not clear on or what confuses you and I'll do my best to clear things up or provide links to alternative ways of explaining the concept.
  3. A slightly more elegant solution is "[0-9]+"; the "+" modifier requires 1 or more of the preceding element - e.g., 1 and 10 are valid but a space isn't. You can then use a.Trim(), if need be. Of course, the "[0-9][0-9\\t]*" also works ("\\t" is Regex escaped (NOT C# ESCAPED) for whitespace, including tabs, spaces and newlines).
  4. So, insofar as rotation is concerned, it starts at 0 radians facing right (due to the unit circle). Now, as for position... when a tile that is 32x32 with an origin in the middle is drawn to position (0, 0) the top left corner is actually at (-16, -16). So, in order to draw tiles based on their top left hand corner, you need to subtract TIleSize / 2 from both rect.X and rect.Y.
  5. GGulati

    [XNA] Input Textbox

    You can develop your own system, or you can use NeoForce Controls for XNA 4.0. And you can always ask for Neoforce-specific help on the AppHup forums.
  6. Actually, there are alternatives. You can quite easily use the Invalidate() method if you create a custom control that inherits from Panel (or PictureBox, or whatever, but Panel has better drawing abilties)... I've done it for my Windows Form Xtension library. FlickerProofPanel.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing; namespace WF_Xtension { /// <summary> /// Creates a panel that is double buffered, and therefore doesn't flicker /// </summary> public class FlickerProofPanel : Panel { /// <summary> /// Creates a panel that flickers significantly less than normal Windows Form panels /// </summary> public FlickerProofPanel() : base() { SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); } } }
  7. I'm working on a game for which, as always, I need sprites. I've used both conventional OOP and components for sprites, but neither of them are suitable for my current project. To clarify, this is a medium-sized project (in the 10's of K LOC range) which I am working on with 2 friends - one for art & sound and the other coding as well. I was exploring Model-View-Controller for the GUI part of the game when I considered using the pattern for the sprites. That is, as a hybrid, almost-component-like system. Each sprite is composed of an Agent (controller), Avatar (model) and Appearance (view). A Contract acts as an intermediary between the three and allows for information sharing between the 3, as well as decoupling the Avatar from the other two, Agent from the Appearance, and Appearance from the Agent (each aspect only needs to be aware of up to 1 other aspect). I tested it in a small sandbox and it seems promising and flexible. There are multiple inheritors from the abstract class of Agent - a PlayerAgent and an EnemyAgent. The former accepts input and passes it to the model to act upon (move around, attack, etc) and the latter uses the world setting to pass instructions to the model (move towards the player, attack if the other's model is within a certain distance, etc). The model accounts for collision, moving around, and other such activities including combat. For the sandbox, that is literally all it does. The appearance renders animation, changes the frame based on the model's actions and applies other cosmetic details, and so forth. The projects (sandbox and actual game) are written in C#/XNA, and I was hoping for some feedback as to whether this set-up would be viable for a reasonably sized game meant for XBLIG release with no extraneous features such as multiplayer. Code below Delegates.cs public delegate void Instruction(Avatar avatar); public delegate bool ValidityCheck(Avatar avatar); Contract.cs public sealed class Contract//Observer and intermediary between Agent, Avatar and Appearance { #region Static #endregion #region Variables Agent m_agent; Avatar m_avatar; Appearance m_appearance; List<Pair<Instruction, ValidityCheck>> m_instructionQueue;//FIFO #endregion public Contract() { m_instructionQueue = new List<Pair<Instruction, ValidityCheck>>(); } #region Methods public void Link(Agent agent, Avatar avatar, Appearance appearance) { m_agent = agent; m_appearance = appearance; m_avatar = avatar; m_instructionQueue.Clear(); } public void EnqueueInstruction(Instruction instruction, ValidityCheck check) { m_instructionQueue.Add(new Pair<Instruction, ValidityCheck>(instruction, check)); } public void EnqueueInstruction(Pair<Instruction, ValidityCheck> instruction) { m_instructionQueue.Add(instruction); } public Pair<Instruction, ValidityCheck> DequeueInstruction() { if (m_instructionQueue.Count > 0) { Pair<Instruction, ValidityCheck> toRet = m_instructionQueue[0]; m_instructionQueue.RemoveAt(0); return toRet; } else return new Pair<Instruction, ValidityCheck>(); } public ValidityCheck PeekAtValidityCheck() { if (m_instructionQueue.Count > 0) return m_instructionQueue[0].Value; else return null; } public void ClearInstructionQueue() { m_instructionQueue.Clear(); } #endregion #region Properties public Agent Agent { get { return m_agent; } } public Appearance Appearance { get { return m_appearance; } } public Avatar Avatar { get { return m_avatar; } } public bool IsActive { get { return m_agent != null && m_appearance != null && m_avatar != null; } } #endregion } Appereance.cs public abstract class Appearance//View aspect of M-V-C { #region Static #endregion #region Variables Contract m_contract; Animation m_anim; Animation.AnimInstance m_animInst; Rectangle m_renderRect; Color m_tint; #endregion public Appearance(Contract contract, Animation anim, string defaultAnimName, int renderWidth, int renderHeight) { m_contract = contract; m_anim = anim; m_animInst = m_anim.CreateAnimationInstance(); m_animInst.ChangeAnim(defaultAnimName); m_renderRect = new Rectangle(0, 0, renderWidth, renderHeight); m_tint = Color.White; } #region Methods public void Update(GameTime gameTime) { m_anim.Update(gameTime, ref m_animInst); QueryAvatar(gameTime); m_renderRect.X = (int)m_contract.Avatar.Position.X; m_renderRect.Y = (int)m_contract.Avatar.Position.Y; } protected abstract void QueryAvatar(GameTime gameTime); public void Draw(GameTime gameTime) { m_anim.Draw(gameTime, ref m_animInst, m_renderRect, m_tint, Microsoft.Xna.Framework.Graphics.SpriteEffects.None, 1.0f); } #endregion #region Properties #endregion } Agent.cs public abstract class Agent//Controller aspect and the user input aspect in M-V-C { #region Static #endregion #region Variables protected readonly Contract m_contract; #endregion protected Agent(Contract contract) { m_contract = contract; } #region Methods public abstract void Update(GameTime gameTime); #endregion #region Properties #endregion } Avatar.cs public class Avatar//Model aspect of M-V-C { #region Static #endregion #region Variables Contract m_contract; Vector2 m_pos, m_movement; #endregion protected Avatar(Contract contract) { m_contract = contract; } #region Methods public void Update(GameTime gameTime) { //check collision and wotnot and other model-y stuff m_pos += m_movement; m_movement = Vector2.Zero; if (m_contract.PeekAtValidityCheck() != null && m_contract.PeekAtValidityCheck()(this))//if there is something to do, see if it can be done m_contract.DequeueInstruction().Key(this);//then do it } #endregion #region Properties public Vector2 Position { get { return m_pos; } set { m_pos = value; } } public Vector2 Movement { get { return m_movement; } set { m_movement = value; } } #endregion } Snippets from InstructionFactory.cs sealed class InstructionFactory { #region Static static InstructionFactory() { //construction here } #endregion #region Variables #endregion #region Methods public Pair<Instruction, ValidityCheck> ConstructMovementInstruction(Vector2 movement) { return new Pair<Instruction, ValidityCheck>( (Avatar avatar) => { avatar.Movement += movement; }, (Avatar avatar) => { return true; } ); //Could be made simpler - the above is for maximum readability since it's so similar to method declaration /* return new Pair<Instruction, ValidityCheck>( avatar => { avatar.Movement += movement; }, avatar => { return true; } ); */ } #endregion #region Properties #endregion }
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!