Jump to content

  • Log In with Google      Sign In   
  • Create Account

alnite

Member Since 07 Nov 2002
Offline Last Active Yesterday, 06:28 AM

#5297471 Is there any reason to prefer procedural programming over OOP

Posted by alnite on 21 June 2016 - 11:38 AM

Lots of great points here.  It really comes to what problem you are solving, and in order to be able to identify when to use what, you'd need experience.  Here's something that I came across not too long ago at work that I solved using procedural.

 

The problem that I was solving was related to caching:

1. Get value from cache

2. If not available in cache, get it from database

3. Then store the value from the database to the cache

 

In Ruby, you can pass an anonymous function to another function.  The function that receives this anonymous function may decide (or not) to invoke.  This is what the function roughly looks like:

 

def get_from_cache(key, &block)
  value = cache.get(key)
  return value if value
 
  value = block.call # call the anon function
  cache.set(key, value)
  return value
end

 

The function is simple enough.  Attempt to get value from cache, if found, return value immediately.  If cache doesn't have the key, invoke another function, and use that function's return value as the value for the key.

 

We can 'chain' this up, creating complex logic structure.  Examples:

 

# Get value from database and cache it
value = get_from_cache("foo") do
  get_from_database("foo")
end
 
# Get value from HTTP and cache it
value = get_from_cache("foo") do
  http("http://www.gamedev.net/posts?key=foo")
end
 
# Or multiple caching layers
value = get_from_cache("foo") do
  get_from_another_cache("foo") do
    get_from_database("foo") do
      http("http://www.gamedev.net/posts?key=foo")
    end
  end
end
 




#5297341 Non-duplicating pairs from a set

Posted by alnite on 20 June 2016 - 12:45 PM

Need to be elaborated more.

 

If it's 6 pairs from a set of 13 numbers, then one of the world won't have any portal at a given time, correct?

 

Gen 0, your set will look like this: [0,1], [2,3], [4,5], [6,7], [8,9],[10,11]

World 12 does not have a portal open.

 

Then, what's the rule for picking the next set?  Is it sequential?  Does this mean that world 0 will always be given the priority to pick the next world?  And World 12 will be lonely until the 12th generation.

 

Example:

Gen 1, set looks like this: [0,2], [1,3], [4,6], [5,7], [8,10], [9, 11].  In which case 12 is lonely again.

Gen 2, set looks like this: [0,3], [1,2], [4,7], [5,6], [8,11], [9, 10].  In which case 12 is lonely again.

 

Edit:

 

Here's a proposal.  Use a queue/stack depending on what order you want them to be, and each world needs to keep track a list of worlds that it has had a portal open to until next reset.  Initially your queue is just the sequence of the world.

 

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

 

Then, pop each world, if there's no world popped yet, keep this world 'open'.  Then pop the next world.  Attempt to link these two worlds together.  If two worlds have been linked together before, then it should fail the linking process, and you would have two worlds 'open'.  Repeat for the next world.  If pairing happens, "close"/"linked" both worlds.  Example:

 

Gen 0

 

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

Pop #0.  Open: [0], Queue: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

Pop #1.  Linked: [0, 1], Queue: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

Pop #2.  Linked: [0, 1], Open: [2], Queue: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

and so on.. until the last one

Pop #11. Linked: [0,1], [2,3], [4,5], [6,7], [8,9], [10,11]. Queue: [12]

 

Gen 1

Reinserts all world back to the queue:

 

Queue: [12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

Pop #12.  Open: [12], Queue: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

Pop #0.  Linked: [12, 0], Queue: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

Pop #1.  Linked: [12, 0], Open: [1], Queue: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

and so on.. until the last one

Pop #10. Linked: [12,0], [1,2], [3,4], [5,6], [7,8], [9,10]. Queue: [11]

 

Gen 2

Reinserts all world back to the queue:

 

Queue: [11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Pop #11.  Open: [11], Queue: [12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Pop #12.  Linked: [11, 12], Queue: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Pop #0.  Linked: [11, 12], Open: [0], Queue: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Pop #1.  Linked: [11, 12], Open: [0], Open [1], Queue: [2, 3, 4, 5, 6, 7, 8, 9, 10]  // since [0,1] has been linked before

and so on.. until the last one

Pop #9. Linked: [11, 12], [0,2], [1,3], [4,6], [5,7], [8,10]. Queue: [9]

 

Gen 3

Queue: [9, 11, 12, 0, 2, 1, 3, 4, 6, 5, 7, 8, 10]

Final Order: [9, 11], [12, 2], [0, 3], [1, 4], [6, 8], [5, 10], [7]

 

 

You can get different linking order by playing around with different insertion order.  I am using the ordering of pairs, you can keep it sequential.  You can also use a stack instead of a queue.  I am using a queue so that the world that didn't get a portal open from previous generation would always get one at the next generation.

 

-- More edit:

 

Here's a list of all the portals:

 

Gen: 0
Queue Before: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
Linked: [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11]]
Queue After: [12]
Link History: {0=>[1], 1=>[0], 2=>[3], 3=>[2], 4=>[5], 5=>[4], 6=>[7], 7=>[6], 8=>[9], 9=>[8], 10=>[11], 11=>[10], 12=>[]}

Gen: 1
Queue Before: [12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Linked: [[12, 0], [1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
Queue After: [11]
Link History: {0=>[1, 12], 1=>[0, 2], 2=>[3, 1], 3=>[2, 4], 4=>[5, 3], 5=>[4, 6], 6=>[7, 5], 7=>[6, 8], 8=>[9, 7], 9=>[8, 10], 10=>[11, 9], 11=>[10], 12=>[0]}

Gen: 2
Queue Before: [11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Linked: [[11, 12], [0, 2], [1, 3], [4, 6], [5, 7], [8, 10]]
Queue After: [9]
Link History: {0=>[1, 12, 2], 1=>[0, 2, 3], 2=>[3, 1, 0], 3=>[2, 4, 1], 4=>[5, 3, 6], 5=>[4, 6, 7], 6=>[7, 5, 4], 7=>[6, 8, 5], 8=>[9, 7, 10], 9=>[8, 10], 10=>[11, 9, 8], 11=>[10, 12], 12=>[0, 11]}

Gen: 3
Queue Before: [9, 11, 12, 0, 2, 1, 3, 4, 6, 5, 7, 8, 10]
Linked: [[9, 11], [12, 2], [0, 3], [1, 4], [6, 8], [5, 10]]
Queue After: [7]
Link History: {0=>[1, 12, 2, 3], 1=>[0, 2, 3, 4], 2=>[3, 1, 0, 12], 3=>[2, 4, 1, 0], 4=>[5, 3, 6, 1], 5=>[4, 6, 7, 10], 6=>[7, 5, 4, 8], 7=>[6, 8, 5], 8=>[9, 7, 10, 6], 9=>[8, 10, 11], 10=>[11, 9, 8, 5], 11=>[10, 12, 9], 12=>[0, 11, 2]}

Gen: 4
Queue Before: [7, 9, 11, 12, 2, 0, 3, 1, 4, 6, 8, 5, 10]
Linked: [[7, 9], [11, 2], [12, 3], [0, 4], [1, 6], [8, 5]]
Queue After: [10]
Link History: {0=>[1, 12, 2, 3, 4], 1=>[0, 2, 3, 4, 6], 2=>[3, 1, 0, 12, 11], 3=>[2, 4, 1, 0, 12], 4=>[5, 3, 6, 1, 0], 5=>[4, 6, 7, 10, 8], 6=>[7, 5, 4, 8, 1], 7=>[6, 8, 5, 9], 8=>[9, 7, 10, 6, 5], 9=>[8, 10, 11, 7], 10=>[11, 9, 8, 5], 11=>[10, 12, 9, 2], 12=>[0, 11, 2, 3]}

Gen: 5
Queue Before: [10, 7, 9, 11, 2, 12, 3, 0, 4, 1, 6, 8, 5]
Linked: [[10, 7], [9, 2], [11, 3], [12, 4], [0, 6], [1, 8]]
Queue After: [5]
Link History: {0=>[1, 12, 2, 3, 4, 6], 1=>[0, 2, 3, 4, 6, 8], 2=>[3, 1, 0, 12, 11, 9], 3=>[2, 4, 1, 0, 12, 11], 4=>[5, 3, 6, 1, 0, 12], 5=>[4, 6, 7, 10, 8], 6=>[7, 5, 4, 8, 1, 0], 7=>[6, 8, 5, 9, 10], 8=>[9, 7, 10, 6, 5, 1], 9=>[8, 10, 11, 7, 2], 10=>[11, 9, 8, 5, 7], 11=>[10, 12, 9, 2, 3], 12=>[0, 11, 2, 3, 4]}

Gen: 6
Queue Before: [5, 10, 7, 9, 2, 11, 3, 12, 4, 0, 6, 1, 8]
Linked: [[5, 9], [10, 2], [7, 11], [3, 6], [12, 1], [4, 8]]
Queue After: [0]
Link History: {0=>[1, 12, 2, 3, 4, 6], 1=>[0, 2, 3, 4, 6, 8, 12], 2=>[3, 1, 0, 12, 11, 9, 10], 3=>[2, 4, 1, 0, 12, 11, 6], 4=>[5, 3, 6, 1, 0, 12, 8], 5=>[4, 6, 7, 10, 8, 9], 6=>[7, 5, 4, 8, 1, 0, 3], 7=>[6, 8, 5, 9, 10, 11], 8=>[9, 7, 10, 6, 5, 1, 4], 9=>[8, 10, 11, 7, 2, 5], 10=>[11, 9, 8, 5, 7, 2], 11=>[10, 12, 9, 2, 3, 7], 12=>[0, 11, 2, 3, 4, 1]}

Gen: 7
Queue Before: [0, 5, 9, 10, 2, 7, 11, 3, 6, 12, 1, 4, 8]
Linked: [[0, 5], [2, 7], [9, 3], [10, 6], [11, 1], [12, 8]]
Queue After: [4]
Link History: {0=>[1, 12, 2, 3, 4, 6, 5], 1=>[0, 2, 3, 4, 6, 8, 12, 11], 2=>[3, 1, 0, 12, 11, 9, 10, 7], 3=>[2, 4, 1, 0, 12, 11, 6, 9], 4=>[5, 3, 6, 1, 0, 12, 8], 5=>[4, 6, 7, 10, 8, 9, 0], 6=>[7, 5, 4, 8, 1, 0, 3, 10], 7=>[6, 8, 5, 9, 10, 11, 2], 8=>[9, 7, 10, 6, 5, 1, 4, 12], 9=>[8, 10, 11, 7, 2, 5, 3], 10=>[11, 9, 8, 5, 7, 2, 6], 11=>[10, 12, 9, 2, 3, 7, 1], 12=>[0, 11, 2, 3, 4, 1, 8]}

Gen: 8
Queue Before: [4, 0, 5, 2, 7, 9, 3, 10, 6, 11, 1, 12, 8]
Linked: [[4, 2], [0, 7], [5, 3], [9, 6], [10, 1], [11, 8]]
Queue After: [12]
Link History: {0=>[1, 12, 2, 3, 4, 6, 5, 7], 1=>[0, 2, 3, 4, 6, 8, 12, 11, 10], 2=>[3, 1, 0, 12, 11, 9, 10, 7, 4], 3=>[2, 4, 1, 0, 12, 11, 6, 9, 5], 4=>[5, 3, 6, 1, 0, 12, 8, 2], 5=>[4, 6, 7, 10, 8, 9, 0, 3], 6=>[7, 5, 4, 8, 1, 0, 3, 10, 9], 7=>[6, 8, 5, 9, 10, 11, 2, 0], 8=>[9, 7, 10, 6, 5, 1, 4, 12, 11], 9=>[8, 10, 11, 7, 2, 5, 3, 6], 10=>[11, 9, 8, 5, 7, 2, 6, 1], 11=>[10, 12, 9, 2, 3, 7, 1, 8], 12=>[0, 11, 2, 3, 4, 1, 8]}

Gen: 9
Queue Before: [12, 4, 2, 0, 7, 5, 3, 9, 6, 10, 1, 11, 8]
Linked: [[12, 7], [2, 5], [4, 9], [0, 10], [6, 11], [3, 8]]
Queue After: [1]
Link History: {0=>[1, 12, 2, 3, 4, 6, 5, 7, 10], 1=>[0, 2, 3, 4, 6, 8, 12, 11, 10], 2=>[3, 1, 0, 12, 11, 9, 10, 7, 4, 5], 3=>[2, 4, 1, 0, 12, 11, 6, 9, 5, 8], 4=>[5, 3, 6, 1, 0, 12, 8, 2, 9], 5=>[4, 6, 7, 10, 8, 9, 0, 3, 2], 6=>[7, 5, 4, 8, 1, 0, 3, 10, 9, 11], 7=>[6, 8, 5, 9, 10, 11, 2, 0, 12], 8=>[9, 7, 10, 6, 5, 1, 4, 12, 11, 3], 9=>[8, 10, 11, 7, 2, 5, 3, 6, 4], 10=>[11, 9, 8, 5, 7, 2, 6, 1, 0], 11=>[10, 12, 9, 2, 3, 7, 1, 8, 6], 12=>[0, 11, 2, 3, 4, 1, 8, 7]}

Gen: 10
Queue Before: [1, 12, 7, 2, 5, 4, 9, 0, 10, 6, 11, 3, 8]
Linked: [[1, 7], [12, 5], [9, 0], [4, 10], [2, 6]]
Queue After: [11, 3, 8]
Link History: {0=>[1, 12, 2, 3, 4, 6, 5, 7, 10, 9], 1=>[0, 2, 3, 4, 6, 8, 12, 11, 10, 7], 2=>[3, 1, 0, 12, 11, 9, 10, 7, 4, 5, 6], 3=>[2, 4, 1, 0, 12, 11, 6, 9, 5, 8], 4=>[5, 3, 6, 1, 0, 12, 8, 2, 9, 10], 5=>[4, 6, 7, 10, 8, 9, 0, 3, 2, 12], 6=>[7, 5, 4, 8, 1, 0, 3, 10, 9, 11, 2], 7=>[6, 8, 5, 9, 10, 11, 2, 0, 12, 1], 8=>[9, 7, 10, 6, 5, 1, 4, 12, 11, 3], 9=>[8, 10, 11, 7, 2, 5, 3, 6, 4, 0], 10=>[11, 9, 8, 5, 7, 2, 6, 1, 0, 4], 11=>[10, 12, 9, 2, 3, 7, 1, 8, 6], 12=>[0, 11, 2, 3, 4, 1, 8, 7, 5]}

Gen: 11
Queue Before: [11, 3, 8, 1, 7, 12, 5, 9, 0, 4, 10, 2, 6]
Linked: [[3, 7], [11, 5], [1, 9], [8, 0], [12, 10]]
Queue After: [4, 2, 6]
Link History: {0=>[1, 12, 2, 3, 4, 6, 5, 7, 10, 9, 8], 1=>[0, 2, 3, 4, 6, 8, 12, 11, 10, 7, 9], 2=>[3, 1, 0, 12, 11, 9, 10, 7, 4, 5, 6], 3=>[2, 4, 1, 0, 12, 11, 6, 9, 5, 8, 7], 4=>[5, 3, 6, 1, 0, 12, 8, 2, 9, 10], 5=>[4, 6, 7, 10, 8, 9, 0, 3, 2, 12, 11], 6=>[7, 5, 4, 8, 1, 0, 3, 10, 9, 11, 2], 7=>[6, 8, 5, 9, 10, 11, 2, 0, 12, 1, 3], 8=>[9, 7, 10, 6, 5, 1, 4, 12, 11, 3, 0], 9=>[8, 10, 11, 7, 2, 5, 3, 6, 4, 0, 1], 10=>[11, 9, 8, 5, 7, 2, 6, 1, 0, 4, 12], 11=>[10, 12, 9, 2, 3, 7, 1, 8, 6, 5], 12=>[0, 11, 2, 3, 4, 1, 8, 7, 5, 10]}

Gen: 12
Queue Before: [4, 2, 6, 3, 7, 11, 5, 1, 9, 8, 0, 12, 10]
Linked: [[4, 7], [5, 1], [2, 8], [11, 0], [6, 12], [3, 10]]
Queue After: [9]
Link History: {0=>[1, 12, 2, 3, 4, 6, 5, 7, 10, 9, 8, 11], 1=>[0, 2, 3, 4, 6, 8, 12, 11, 10, 7, 9, 5], 2=>[3, 1, 0, 12, 11, 9, 10, 7, 4, 5, 6, 8], 3=>[2, 4, 1, 0, 12, 11, 6, 9, 5, 8, 7, 10], 4=>[5, 3, 6, 1, 0, 12, 8, 2, 9, 10, 7], 5=>[4, 6, 7, 10, 8, 9, 0, 3, 2, 12, 11, 1], 6=>[7, 5, 4, 8, 1, 0, 3, 10, 9, 11, 2, 12], 7=>[6, 8, 5, 9, 10, 11, 2, 0, 12, 1, 3, 4], 8=>[9, 7, 10, 6, 5, 1, 4, 12, 11, 3, 0, 2], 9=>[8, 10, 11, 7, 2, 5, 3, 6, 4, 0, 1], 10=>[11, 9, 8, 5, 7, 2, 6, 1, 0, 4, 12, 3], 11=>[10, 12, 9, 2, 3, 7, 1, 8, 6, 5, 0], 12=>[0, 11, 2, 3, 4, 1, 8, 7, 5, 10, 6]}

Gen: 13
Queue Before: [9, 4, 7, 5, 1, 2, 8, 11, 0, 6, 12, 3, 10]
Linked: [[4, 11], [9, 12]]
Queue After: [7, 5, 1, 2, 8, 0, 6, 3, 10]
Link History: {0=>[1, 12, 2, 3, 4, 6, 5, 7, 10, 9, 8, 11], 1=>[0, 2, 3, 4, 6, 8, 12, 11, 10, 7, 9, 5], 2=>[3, 1, 0, 12, 11, 9, 10, 7, 4, 5, 6, 8], 3=>[2, 4, 1, 0, 12, 11, 6, 9, 5, 8, 7, 10], 4=>[5, 3, 6, 1, 0, 12, 8, 2, 9, 10, 7, 11], 5=>[4, 6, 7, 10, 8, 9, 0, 3, 2, 12, 11, 1], 6=>[7, 5, 4, 8, 1, 0, 3, 10, 9, 11, 2, 12], 7=>[6, 8, 5, 9, 10, 11, 2, 0, 12, 1, 3, 4], 8=>[9, 7, 10, 6, 5, 1, 4, 12, 11, 3, 0, 2], 9=>[8, 10, 11, 7, 2, 5, 3, 6, 4, 0, 1, 12], 10=>[11, 9, 8, 5, 7, 2, 6, 1, 0, 4, 12, 3], 11=>[10, 12, 9, 2, 3, 7, 1, 8, 6, 5, 0, 4], 12=>[0, 11, 2, 3, 4, 1, 8, 7, 5, 10, 6, 9]}
 

 

Notice that it takes 14 generations to go through them all (number of worlds + 1), and the last generation only has two portals open between #4-#11, and #9-#12, while the rest of the worlds are portal-less.  Depending on which is stricter requirements, you can keep it to 13 generations before reseting the link history just knowing that #4-#11 and #9-#12 will never have portals together.




#5296519 how can neural network can be used in videogames

Posted by alnite on 14 June 2016 - 12:54 PM

Strange that nobody mentioned this:




#5293819 Designing UI library - positioning items in containers

Posted by alnite on 27 May 2016 - 10:44 AM

It's been a while since I wrote my own UI library, but here's my opinion.  Take it with a grain of salt:

 

Preferred size/min/max

I am not in favor of preferred size, min, or max.  I think this pollutes the logic.  Consider two child items side by side, both with preferred size of 100.  Container is resized to 150, what is the size of each child item?  If your answer is 75, then why bother with preferred size at all?  Why have a parameter at all only to be ignored?

 

Instead, each child should be responsible in its own proper rendering and logic in any size.  By any size, I mean even down to 1x1 pixel.  No minimum size, no maximum size.  You have a button, that button better works even when its 1x1.  You have a radio button, it better works at 1x1.

 

You can enforce minimum size at the container level, but child item (which cannot contain another child) should be able to handle any size.  Object positioning should be handled by the container, and any items should not dictate to its container how it should be positioned, neither preferred, min, nor max.

 

The reason why is that I have worked on some custom UI library that follows this Java's swing approach, and it has these preferred size, min, and max etc, and they dictate the way the container align and position its children.  It's hard to resolve conflicts at the container level if the child items can dictate to its container how to position itself.  One child say my min is 100, another say my min is 150, and container is resized to 200, which one should you resize?

 

It gets worse if child items are engineered with these preferred, min and max in mind, that certain logic starts to fail when the size goes beyond or lower than these arbitrary thresholds.  "Since my size won't ever go lower than 100, right?, so I'll draw this 5x5 important UI element at exactly the 95th pixel"  Guess what, your width is now 80, and that important UI element is now gone.  Great.

 

So, no min, max, or preferred at all.  As a matter of fact, maybe let the container tells its children their size.




#5293813 Cloudhosting a C# Console Application utilizing UDP

Posted by alnite on 27 May 2016 - 10:03 AM

Actually most server apps I know of lack of a UI frontend.  That does not mean it can't have a UI frontend, just depends on your use case.

 

There are a few server "engines" out there that's been mentioned several times like SmartFox, though I believe it's Java, and I am not sure if it's the 'goto' service.  And in regards to AWS to Azure, it comes to personal preference.  Do understand that once you choose one, you'd usually 'marry' that platform.  It'll be another engineering task to move from one to another.




#5293633 Do you usually prefix your classes with the letter 'C' or something e...

Posted by alnite on 26 May 2016 - 12:31 PM

I tend to use verb/noun/adjective to describe methods, classes, and interface.  Collidable, for example, is an interface.  There are a few cases where it may not be immediately clear at first glance, in which case a simple "Go To Definition" would suffice.

 

The only prefix I use is underscore for reserved class/global variables that I certainly don't want conflicts to happen.  Because you have to be pretty deliberate to use an underscore as the first char.  Even that does not happen a lot.




#5292941 How should I develop this game?

Posted by alnite on 22 May 2016 - 04:37 PM


because I know a single person with no team can't really do something good in this area

 

Actually, yes you can, but it does take a lot of time and dedication.

 

 


I want to develop an RPG game. It's not for me, or for many people. It's only for one special person. I have one month to do this, and I don't know where to start. 

The game would be a story that simulates the butterfly effect. The player will have many choices in many parts of the story, and choosing something will cause a different ending.

 

I think this is a little too much for a one-man one-month project.  Multiple ending paths isn't easy to do.  Being able to architect a game world where different actions lead to different things require a lot of iteration and testing.  You really have to know how to code a game well before taking this task, considering that you are new to game development.

 

If you are not familiar with game development, your initial struggle would be figuring out how animations, collisions, and different game mechanics work.  Different types of games require different technology.  For example, A* is not required for a fighting game, but maybe required for an RPG depending how you present it, and a very robust version is required for an RTS game.  What you need to learn and do really depend on what your game look like and how to play it.

 

So, scoping.  If you ask me, in one month, it's probably more feasible to do a pure text-based adventure game.




#5278639 best way to write clean code

Posted by alnite on 29 February 2016 - 12:06 AM

1. DOTADIW

 

For example: If you have a function called "CreatePath()", make sure all that function does is create a path and nothing else.  Make sure you test it such that it can handle any combination of parameters and corner cases such that it has exactly ZERO (0) bugs.  "CreatePath" cannot call "CreateUnit" or any other functions that might dilute and increase its complexity.

 

 

2. Don't be afraid to refactor and rewrite parts of your code.

 

As you add more logic to your code, refactor is inevitable.  Don't wait to refactor until the last step.  One cause that leads to spaghetti code is people are afraid to create new bugs that they keep monkey-patching on top of what was originally a perfectly fine codebase.  I have been seeing this so many times in my professional life doing code review.  People are so afraid modifying an existing function to make implementation less complex, and would rather put another layer of complexity.

 

Me: "You can just edit that one function to accept an extra parameter, and it will be easier."

Them: "Well, I am not sure what it does and I don't want to break it" (or some other lame excuse like how he has to update the tests)

Me: "But now you just duplicated the code, and next developer will be confused which function to use"

 

 

 

3. Write Automated Tests

 

Test, test, test your code, and write a separate program to test your code.  In all my professional life, nothing have given me better confidence in my code until I have written automated tests for my code.  Sure, it's an annoying thing to do when you write your tests for the first time (ah geez, another shit to worry about), but the confidence you get from running one single command and have ALL your code tested and validated in less than a minute is just too good to pass up.

 

Follow #1 above to make it easier to write your unit tests.  Follow #1 above to make it easier to write functional tests.  If your code is a spaghetti, your tests will be a spaghetti too, and it will annoy the heck out of you.

 

 

4. Document Your Code

 

Another thing that most developers avoid (after writing tests) is writing documentation.  You HAVE TO write documentation to your code.  It sorts of gives your code that final conclusive stamp of approval and seal the envelope.  Writing documentation puts your mind into a 3rd person perspective.  I have found so many design flaws when writing documentation.  For example, let's say your CreatePath() function is badly written that it internally calls CreateUnit() and CreateEnemy().  Writing tests will make you aware of this, and writing documentation will make you reconsider what kind of parameters to accept to avoid calling CreateUnit() and CreateEnemy().

 

If tests make you aware about the internal working of your code, documentation makes you aware of how components in your code play with each other.  Writing documentation is a form of rubber ducky programming.  You are trying to explain to some other (imaginary or not) person who is clueless about how your code works.

 

 

#3 and #4 are your worst enemies.  Somehow developers avoid them like plague thinking they have godlike coding ability that no tests is ever required, and no documentation is ever necessary.  "Code should be self-documenting anyway" rolleyes.gif, I always laugh at that statement.




#5271790 Resolving Creative Differences

Posted by alnite on 18 January 2016 - 10:51 PM

Who is in charge of what?

 

If you have done any game development professionally, you will learn that the game that comes out won't be the exact match of what you are thinking.  You have to let go the control sometimes.  This is not just your game.

 

When this kind of problem arises, usually people would do AB testing.  Create both, and see what works better.  Peer feedback is the most useful thing in video game development.  I am sorry to say that most likely your idea sucks, and so is his (and mine, and everyone else).  We rarely get the first implementation correct.  Peer feedback is important as it gives you honest reviews if game is fun or not.  You'd most likely end up with something completely different than any of you two could imagine.




#5265007 Why didn't somebody tell me?

Posted by alnite on 05 December 2015 - 07:29 AM

There is a Search Tools in Google Search that allows you to filter results based on time.

 

One time someone in my office did this during a meeting and everyone was like "WAIT, YOU CAN DO THAT??"




#5264676 Indie Game Company Names

Posted by alnite on 02 December 2015 - 06:49 PM

Zombie Rose (you know, rise, rose, risen, a little pun here.)




#5262769 Software Tool Selection Process - Improvements please

Posted by alnite on 19 November 2015 - 01:05 PM

 


Unity wouldn't be here if the original developers decided to use an existing game engine

Unity was conceived from the very beginning as a middleware package - it wasn't like they built a game and spun the pieces into an engine after the fact.

 

Which makes it sort of an exception to this whole discussion. If your aim is to build brand-new middleware, then building from scratch is clearly indicated.

 

 

Maybe I misunderstood, but isn't it the discussion of this thread?  Given Software Tool X, shall I rewrite or use it?




#5262651 Software Tool Selection Process - Improvements please

Posted by alnite on 18 November 2015 - 04:53 PM

There is nothing wrong writing your own.  Unity wouldn't be here if the original developers decided to use an existing game engine.  It's just like a natural selection.




#5261425 How hard it is to live from games as indie developer?

Posted by alnite on 10 November 2015 - 03:34 PM

Technical expertise and making money are two different things.

No one here is stopping you from making games, just don't expect making profits from it.




#5259816 How to cope with code in different languages?

Posted by alnite on 30 October 2015 - 06:07 PM

My main concern is that developers should start treating their code as assets.  People always get opinionated about programming languages.  X is better.  Y is faster.  Z is easier.  Whatever your preferred language of choice is, it doesn't really matter because you still have to put in the code, and that's where it takes the most of your development time, not your language being slower (or whatever).  You have done the hard work, but now you are thinking of scrapping all that, and I hope it's not just because of some arbitrary reason like "C++ is better".

 


@alnite, My problem with Delphi/Rad Studio does not stem from the codebase in general, but rather the way Embarcadero is taking the product as well as the quality of the IDE itself. I have the IDE crash on me at least once a day. I end up chasing quirks deep in the VCL source, or rattling my brain trying to understand their Direct2D implementation since the docs are not that amazing. And frankly, as someone that has decades of programming experience but just trying to finish my first big game project, Pascal is not the way to go.

Please dont get me wrong. I love Delphi, but it will never match VS in term of power. I just watched a video on the new DirectX debugging features of VS2015 and I was blown away with how powerful it is and how deep you can investigate. Yet, interface-wise, nothing matches the speed at which you can pump out native Win32/64 apps.

Embarcadero isn't the same since Nick Hodges left...

And alnite, you're totally right, a game doesn't have to be written in C++. But I believe that using Delphi will make things more complicated. The first time around anyways!

 

From what I get reading your posts, it seems that you used Pascal for the editor, not for the game itself.  I don't see much wrong with it.  If you are inches away from completing the game, just hammer through it, finish it in Pascal, despite the IDE challenges.  Even if the game is written in Pascal, if you are *that* close in finishing the game, just finish it.  This happens all the time in studios, and that's because it makes sense financially and time-wise.

 

Future shiny version can be written in C++ if you prefer.






PARTNERS