Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

I have some new habits.

Started by Tutorial Doctor Apr 6, 2014 at 8:48 PM 79 replies 17.2k views
Original Post
Tutorial Doctor
Tutorial Doctor

Okay, I have some new programming habits. I need to know if they are practical.

Why use True/False?


on = True
off = False
 
if light.on then
     JumpForJoy()
end

Sometimes I don't like the names of standard functions:


function Display(text)
    print(text)
end

I really like to use Synonyms for functions that do similar but different tasks.


Begin()
Start()
Commence()
Play()
 
End()
Finish()
Conclude()
Stop()

Being descriptive with my argument names:


function Walk(speed)
       speed = true
end
 
if slowly then
     MakeASadPuppyFace()
end
 
Walk(slowly)

Anyone have any peculiar programming habits that could be of some help?

In other words, any way I can make my code more human-readable?

They call me the Tutorial Doctor.
dr01d3k4
dr01d3k4

I don't understand what's going on here.

1) In your first code snippet, you define on and off (Lua uses lowercase true and false keywords), but not light. Saying


if (light.on) then

is the same as


if (light.on == true) then

if that's what you're asking.

If you mean using


if (light == true) then

then to me, that's not clear as "light" would be an an instance of a light object. light.on or lightOn would be better.

2) As you're using Lua, you could just write


local display = print;

This also preserves print's vararg ability.

3) As long as you're clear and consistent (if you use "start" in one place, you use it in all others, and the correct antonym "stop" in all others too), this doesn't matter.

4) What is going on here? Your function won't work properly because only tables, userdata and functions are passed by address in Lua. Also "slowly" is an unclear name.

Bacterius
Bacterius

Why use True/False?

That really just looks like a boolean property "on" of the "light" object. Usually "True" is implicit as in first order logic, simply stating "P" means the predicate P is true, so "if light.on then" translates to "if the predicate light.on is true then". Types and variables are not the same thing.


Sometimes I don't like the names of standard functions:

I wouldn't recommend doing this. It might look cute in the short term but once you work with other people they will have no idea what you mean by "Display". Does it display things on a window? Does it print them out in the console? Does it do anything else in addition to that? Unless your function actually does something more than just being a pass-through to an existing standard function, you should just use the standard function, it's clearer and idiomatic. Otherwise everyone rolls their own version of function and type names and it's harder to understand other people's code. If you must, make it an alias instead of writing useless wrapper code, but I don't find it a good habit.


I really like to use Synonyms for functions that do similar but different tasks.

It really depends on your code. In most cases it's not advisable since it's harder to immediately know what a function does ("is it Begin() that does X? no, wait, that would be Start().. or Play()... lemme check the code...") but in a few select cases it might make sense depending on what you are writing. I would honestly think hard about whether it is meaningful to do this, because you could waste a lot of time confusing yourself - and others - down the road with all these identical-sounding functions.


Being descriptive with my argument names:

Being descriptiive with argument names is a good thing. Though in your given example the code might look cute with the grammatically correct "walk slowly" function call, but why is speed a boolean variable? Shouldn't it be a floating-point variable giving the speed in units per second, or at least an enum like "slow", "normal", "fast" or similar? "Slowly" is also not very precise - if you just want an argument that says whether to move "slowly" or "quickly", then you should probably just call the argument itself "slowly", or make it accept an enum with two values "slowly" and "quickly". That's much more expressive if you don't intend to actually pass in a speed but only one of two options.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”
Tutorial Doctor
Tutorial Doctor

Good points.

the code:


if light.on then
 
end

is an example of how I might use "on" to mean "true."

so the code would be :


light.on = true
light.off = false
 
if light.on then
 
end

This is distinguished from:


fan.on = true
fan.off = false

I have actually used the quickly and slowly adjectives by assigning numerical values to them, which set the speed of the walk.


if Walk(slowly) then
velocity = 1
end
 
if Walk(quickly) then 
velocity = 3
end

Note: I am using the word velocity instead of speed here (my actual code is not so confusing, I will post a snippet in another reply.) I also don't set the velocity this way, but this is one way I could do it.

The walk function would return the boolean value:


function Walk(speed)
    speed = true
    return speed
end

I used this for my senses system so that I could type:


if See(door) then
   TurnLeft()
end

Where the See() function checks a collision between an object and the door object, and returns true if the collision happens.

Then I can see all types of things.


if See(person) then
if See(wall) then

Slowly and quickly are interpretations of the numerical values. For instance, when you think "slowly" you think not as fast as "quickly."

I can explicitly change the interpretation by adjusting the numerical value to make quickly mean "3 times as fast."

They call me the Tutorial Doctor.
Tutorial Doctor
Tutorial Doctor

Example from a working script:


-----------------------------------------------------------------------------------
-- Maratis
-- Jules script test
-----------------------------------------------------------------------------------
on = true
off = false

-- Get objects
Player = getObject("Player")
Head = getObject("Head")
eyes = getObject("Eyes")
ears = getObject("Ears")
box = getObject("Box")
monkey = getObject("Monkey")
building = getObject("Building")
smallBox = getObject("small box")
door = getObject("door")

soundplay1 = off
soundplay2 = off
soundplay3 = off
soundplay4 = off


seeBox = getObject("SeeBox")--sound
seeMonkey = getObject("SeeMonkey")--sound
seeBuilding = getObject("SeeBuilding")--sound
tack= getObject("Tack")--sound
rightway = getObject("rightway")

--Text Overlay
camera = getObject("Camera0")
gui = getScene("gui")

--Get text Objects from another Scene to overlay on first scene
see = getObject(gui,"see")
touch = getObject(gui,"touch")
hear = getObject(gui,"hear")
collect = getObject(gui,"collect")
state = getObject(gui,"state")
hear_distance =getObject(gui,"hearDistance")

--Project a scene over a camera
enableCameraLayer(camera,gui)

--Emotional States
mood = 5 --initial mood (normal)
sad = false
happy = false
normal = true

--setText(txt_readout,distance)


--SENSES
--SEE
function See(object)
	if isCollisionBetween(eyes,object) then
		seenObject = getName(object)
		setText(see, "I see a ".. seenObject)
		seeing = true
		
		return true
	else 
		--setText(see,"I see nothing")
		seeing = false
	end
end

--TOUCH
function Touch(object)
	if isCollisionBetween(Player,object) then
		touchedObject = getName(object)
		setText(touch, "I feel a ".. touchedObject)
		touching = true
	else setText(touch,"I feel nothing")
		touching = false
	end
end

--SPEAK
function Speak()
	if See(box) then
		if soundplay1 == off then
			playSound(seeBox)
		end
		soundplay1 = on
	else 
		soundplay1 = off
	end
	
	if See(monkey) then
		if soundplay2 == off then
			playSound(seeMonkey)
		end
		soundplay2 = on
	else
		soundplay2 = off
	end
	
	if  See(building) then
		if soundplay3 == off then
			playSound(seeBuilding)
		end
		soundplay3 = on
	else
		soundplay3 = off
	end
	
	if  See(door) then
		if soundplay4 == off then
			playSound(rightway)
		end
		soundplay4 = on
	else
		soundplay4 = off
	end
end

--ACTIONS
function Jump(object)
	if seeing then
		setGravity({0,0,-4})
		addCentralForce(object,{0,0,9},"local")
	end
end

function Destroy(r,s,t)
	deactivate(r)
	deactivate(s)
	deactivate(t)
end

function Collect(object)
	if isCollisionBetween(Player,object) then
		Destroy(object)
		playSound(tack)
		setText(collect,"I collected a " .. getName(object))
	end
end


--mood = {sad = false, normal = false, happy = false}
--mood.sad, mood.normal, moode.happy

function ChangeEmotion()
	
	if mood >=0 and mood < 4 then
		sad = true
		normal = false
		happy = false
		--setText(state,"I am sad")
	end
		
	if mood>=4 and mood <=6 then
		sad = false
		normal = true
		happy = false
		--setText(state,"I am normal")
	end
		
	if mood >6 and mood <=10 then
		sad = false
		normal = false
		happy = true
		--setText(state,"I am happy")
	end
end

function TriggerEmotionChange()
	if See(box) then
		mood = 10
		setText(state, getName(box) .. "es " .. "make me glad")
	elseif See(monkey) then
		mood = 3
		setText(state, getName(monkey) .. "s " .. "make me sad")
	elseif See(building) then
		mood = 5
		setText(state, getName(building) .. "s " .. "make me turn around in circles")
	
	elseif See(door) then
		mood = 5
		setText(state, "This is a locked " .. getName(door))
	else
		setText(state,"Thinking...")
	end
end


-- Scene Update
function onSceneUpdate()
	ChangeEmotion()
	TriggerEmotionChange()
	Move()
	
	Touch(building)
	Touch(monkey)
	Touch(box)
	Touch(door)
	
	See(box)
	See(monkey)
	--See(building)
	Speak()
	
	Hear(monkey)
	Collect(smallBox)
	--Collect(box)
	--Collect(monkey)
	See(door)
	
	--Jump(Player)
	--Destroy(txt_seeing,txt_hearing,txt_touching)
	
end


They call me the Tutorial Doctor.
dr01d3k4
dr01d3k4

light.on = true
light.off = false
 
if light.on then
 
end

This could get confusing. When you want to toggle the on/off state, you have to remember to set both so that you don't have a light that's both on and off. Also, off is implied by not on and so isn't even required.

Your Walk() example is confusing too. It returns true in all cases and isn't clear what's going on. For the see example, using "canSee(object)" would be better as just "see(object)" could imply that you want to look at the object instead.

In your full code example, your functions like "see" and "touch" are doing multiple things and as I said, from their name aren't clear on purpose.

Tutorial Doctor
Tutorial Doctor

For the see example, using "canSee(object)" would be better as just "see(object)" could imply that you want to look at the object instead.

Great suggestion! I actually threw together that script without considering how it would sound grammatically (I do have to fix this). I should be returning "seen" not true.

I was thinking of


if Seen(object)

but I want to use the word "seen" as a Boolean.

something like


if boy.seen 

The see() and touch() functions are doing multiple things for the purposes of the level I am doing, but all they basically do is get a collision and return a Boolean.

Now that I think about it, I need to compile a Demo of my Senses system (although I wanted to clean it up first).

Edit: I could do:


if boy.Sees(object) then
They call me the Tutorial Doctor.
NewVoxel
NewVoxel

Tutorial doctor this is all an ellaborate ruse isn't it? No one in their right mind would share such valuable programming techniques.

Your authority is not recognized in Fort Kick-ass http://www.newvoxel.com
Tutorial Doctor
Tutorial Doctor

How the Synonyms are used:


menu = Menu() --Creates a new menu
menu.Start() --Starts the menu
menu.End() --Stops the menu
----------------------------------------------------------------------------------------

--getScene("sceneName")
--getScenesNumber()

cut_scene = newCutScene() --Creates a new cut-scene
cut_scene.Play()		 --Plays the new cut-scene
cut_scene.Stop() --Stops the new cut-secene

--getScene("sceneName")
--getScenesNumber()

cut_scene_2 = newCutScene() --Creates a new cut-scene
cut_scene_2.Play()	changeScene(scene) --Plays the new cut-scene
cut_scene_2.Stop() --Stops the new cut-secene
-------------------------------------------------------------------------------------
--loadLevel("levels/myLevel.level")

level1 = Level() --Creates a new level
level1.Begin() = 		loadLevel("levelName") --Starts the new level
level1.Finish() --Stops the new level
-------------------------------------------------------------------------------------
--getObject(« objectName »)
--activate(object)
--deactivate(object)
--isVisible(object)
--isActive(object)

prop1 = Prop()=	--Creates a new prop
prop1.Create(room) --Creates the mesh for the new prop
prop1.Destroy()
They call me the Tutorial Doctor.
JTippetts
JTippetts

--Emotional States
mood = 5 --initial mood (normal)
sad = false
happy = false
normal = true
Is it really your intention that an object can be happy, sad and normal all at the same time? Because if that is not your intention, then there is really no need for these sad, happy and normal booleans. Especially since their state is set depending on mood, so you apparently already have all the information you need about their mood without the booleans. Doing it this way is just asking for trouble.
Tutorial Doctor
Tutorial Doctor

Good point JTippetts. My goal is that an object can be varying degrees of happy and sad, as in happy, happier, very happy. The setup doesn't yet reflect the range of emotions I want to create.

The mood effects the state of the object.

So, the mood ranges from 0 to 10.

If the mood is between certain lower values, the state of the object is more sad. I just wanted to use words to convey the mood rather than numbers.

Sort of how it works in the Sims. The the state of the sims constantly changing based on other variables.

So at first, the Sim might be happy, but if the cleanliness of the house is low, the Sim might become progressively more sad.

I might need to use another word other than mood now that I think about it.

I could make the sad variable numbers between 0 and 4 (as a range). But I haven't really haven't made my code as complex as it will be yet. I just needed it working for proof of concept.

Eventually I want a full Emotion class as well as a Senses class. And I want all of my syntax to flow like an English sentence. So I will be making it object oriented also.

As you can see, the implementation is very straightforward.

See(whateverObjectYouWantToSee)

But I create special cases where seeing an object can set a mood, thereafter affecting the state of the player. And if a state has changed, then the character might play a certain animation or something to visually convey the mood. Right now I am just using a sound to convey the mood.

They call me the Tutorial Doctor.
JTippetts
JTippetts

Good point JTippetts. My goal is that an object can be varying degrees of happy and sad, as in happy, happier, very happy. The setup doesn't yet reflect the range of emotions I want to create.

The mood effects the state of the object.

So, the mood ranges from 0 to 10.

If the mood is between certain lower values, the state of the object is more sad. I just wanted to use words to convey the mood rather than numbers.


Sounds like you're struggling toward a form of fuzzy logic. I'd stick with the numbers and leave the words for presentation to the user. It is useful for the script to know that an object sits on the sad/happy index at 0.56, whereas it is far less useful for the script to know that the object is 'somewhat happier than normal'. 0.56 it can calculate with; the other is just meaningless.

Eventually I want a full Emotion class as well as a Senses class. And I want all of my syntax to flow like an English sentence. So I will be making it object oriented also.


I highly recommend against trying to combine natural language processing with fuzzy logic. Each can be complex; together it could be far more of a project than you really need to implement a simple Sims-like AI. Just stick with the fuzzy numbers on the back end and save the English for the player.
Tutorial Doctor
Tutorial Doctor




. It returns true in all cases and isn't clear what's going on

Hehe. I am currently having an issue with this. I am working on clearing up the code a bit, with the good suggestions here.

They call me the Tutorial Doctor.
Tutorial Doctor
Tutorial Doctor




It is useful for the script to know that an object sits on the sad/happy index at 0.56, whereas it is far less useful for the script to know that the object is 'somewhat happier than normal'. 0.56 it can calculate with; the other is just meaningless

Indeed, to the computer it is meaningless, but to me it does mean something. That is the main reason for doing it. It makes more sense for me to set a state to happy than to set a state to a numerical value.

So perhaps it is a way for me to interpret the meaning of .56 rather than a way for the computer to interpret what sad means. Or perhaps it is a way for the computer and I to speak in our own languages and still understand each other?

Thanks for the new vocab-- fuzzy logic. hehe. I like it.

Oh, and thanks for all of the suggestions, I am going to change some things because of it.

They call me the Tutorial Doctor.
Tutorial Doctor
Tutorial Doctor

I am liking this fuzzy logic stuff. It looks exactly like what I want my code to look like:


IF temperature IS very cold THEN stop fan
IF temperature IS cold THEN turn down fan
IF temperature IS normal THEN maintain level
IF temperature IS hot THEN speed up fan

I was actually thinking of making a function named Be(). This function would be part of some type of conjugation class. Then I can type


boy.was(angry) 
boy.is(angry)
boy.willBe(angry)
They call me the Tutorial Doctor.
Tutorial Doctor
Tutorial Doctor

For reference, here is a video on fuzzy logic, which is perfect for what I am going for, because I am somewhat simulating human thinking process.

This video describes exactly what I am thinking of!!! Wow.

Another Video

Found a detailed article on fuzzy logic:

http://www.seattlerobotics.org/encoder/mar98/fuz/fl_part1.html#INTRODUCTION

They call me the Tutorial Doctor.
Tutorial Doctor
Tutorial Doctor

It seems that an object can either be considered tall or short with boolean logic, but with fuzzy logic, an object can be considered "more tall" or "less short"

So an object could be 30% tall, where a value would be set for 100%tall (depends on the scale of the world).

If on a scale 100% tall was 10ft, then 30% tall would be 3ft. This would yield varying degrees of tallness.

mood would work the same way. Originally though, i was using the cut-off point method. But the fuzzy logic sounds better.

New habit adopted!

They call me the Tutorial Doctor.
frob
frob




Sort of how it works in the Sims. The the state of the sims constantly changing based on other variables.

So at first, the Sim might be happy, but if the cleanliness of the house is low, the Sim might become progressively more sad.

I might need to use another word other than mood now that I think about it.

The Sims uses a series of numbers, called "motives". Some of them visible to the player, some of them not. There are additional conditions to rank against, such personality traits, lot-based values like "At Nightclub", buffs and debuffs (e.g. fatigued), and so on.

Each interaction advertises to the motives, and some can be negative. For example, "take shower" might have advertise +10 hygiene, +5 if you have some neatness traits, and -50 if you have "slob" trait. "Watch TV" might advertise to +10 fun, but also +20 for "couch potato" trait, +10 for children, -50 for the techniphobe trait, and so on. When a Sim is idle and looking for something to do, all the nearby interactions are computed against their motives, traits, skills and other values. Interactions can be marked as "repeatable", if they aren't marked that way the interaction is removed from the list if it happened in recent memory. So you might have "watch TV" at 315, "make food" at 312, "play ball" at 311, "do homework" at 17, and a bunch of other interactions all with their score.

The numbers get combined, sorted, and one of the top few values is randomly selected.

Designers put a lot of work into properly tuning the values. Over the years a few items have had a bit too high or too low values, which usually get fixed in a patch. For example, just after they were introduced in Sims 3 University, Sims were pulling out their smart phones a bit too frequently, but the tuning values were adjusted in the next patch.




Why use True/False?

People have debated about the merits of using bools versus enumerations for decades.

It can be good in some cases, perhaps in the strongest argument by making parameters more descriptive rather than just DoSomething( someValue, true, false, false, true, false) where people unfamiliar with the functions can see what the values are used for. They can also add burden to the programmer, needing to convert from one component's enum value to another system's enum value, even though the programmer knows the only valid values are 0 and 1. Programmers frequently end up casting them away or writing a conversion function to turn collections of named values into bools, consuming potentially-precious cycles on interpreting values. It is highly situation specific.

Boolean values are more ideal in some situations, less ideal in other situations. As the programmer the choice is yours to make, along with its attendant consequences.

spinningcube
spinningcube

My take on this. As long as you move away from encapsulating data in objects and rather work on data in its rawest form and sending them to functions - the better.

However what I see in your approach is some form of super-object-oriented or semantics based rule language. As I abhor OOP and especially OOP design based principles, this would be the pinnacle of bad programming practice as it cements the use of objects that make the problem more complex and harder to solve.

Sorry to sound so harsh, but I really believe that what you do will bite you in the end.

You just create massive confusion like this and your code would become unmaintainable.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.