ID:1809475
 
Hi, I'm relatively new here (first started exploring Dream Maker in Jan 2015), and am a total noob in programming. But I thought I'd start a thread for myself to just record my journey in learning BYOND. I'm not really looking for replies to my post, but if you have feedback for me, I'd be more than glad to listen. Again, do remember I am a total noob in programming - so uhm, go easy on me :D

Anyway, here's some background about myself.

Note: where I use "->", it's an answer to my own questions. I'll do this as well for future posts.

What system do I use?
-> I can't really afford a better system, but I use a laptop with these specs:
Intel Atom 1.33Ghz processor
2.0 GB installed memory
32-bit OS, x64-based processor

What's my favorite game on the web?
-> I'm not much of an RPG fan (although I realise a lot of popular games here are RPG-based), but I'm mostly interested in empire building or economy simulation games, with http://www.cosmicsupremacy.com especially close to me (I'm a player-admin there)

Do I know Java? or C++?
-> Nope.. I've mostly struggled with object-oriented languages.

What 'programming languages' do I know?
-> The closest I come to it is VBA in MS Excel, which happens to be something I use quite a lot in my work. But I understand it's procedural programming - and I've always had a hard time transitioning to object-oriented languages.

Have I attended any computer science courses or received any formal training?
-> Nope.. I'm an accounting & finance graduate - and work in that area. So programming is just a side interest that I try to learn casually. And I've been told it shows in the way I set up my scripts too (I wish I knew how to make concise and efficient codes - but that's obviously a skill that requires a lot of practice to master)

Do I have experience creating games?
-> Since I've only managed to wrap my head around VBA so far, I've mostly tried making games in Excel. Clunky I admit, but one of my proudest creations is a 7 Hand Poker game (originally on the MSN games network) that even comes with an AI. A video of it is here: https://www.youtube.com/watch?v=rK_FZnmGNcU.

Why am I trying BYOND?
-> Because I find other game engines like Unity to be too steep a learning curve, and I enjoyed reading the DM guide for developers here, which had some youtube videos by Albro1 too that I found nice to follow while reading the guide (that gave me context of the video). https://www.youtube.com/watch?v=k4FhvlaHv7k.

Do I think I can pick up BYOND?
-> It looks very interesting - and I'm proud to say I've actually managed to get a few things going, thanks to some of the tutorials. Very early stages, but better than nothing I suppose. I do have a tendency to not persist in learning things, or approach things in a structured way - so I apologize in advance if I appear to be skipping around different topics and learning only the things that I'm interested in at a particular point in time. It's my way of handling the overwhelmingly large amount of info and demos you guys have put up.
Lesson #1: Animating characters

I've been trying to find the Youtube video I watched to learn about creating animations - but I can't seem to find it now. I'm sorry I can't give you credits at the moment, but I'll be sure to put it in once I remember which one(s) I watched to learn about this.

So I started out by creating a "New Environment". Then created a "New.." "Icon File".

I got my pixel art from a blog I like for his game art designs: http://2dgameartforprogrammers.blogspot.com. , using Inkscape (and a bit of MSPaint) to scale it to a 32x32 pixel image. I also fiddled with the other frames for animation, and I was actually quite pleased with the results. dmi file can be found on my Google Drive here: https://drive.google.com/file/d/ 0BxRVqwhZz061Z0w5MGt2T2V1Y0U/view?usp=sharing (I don't know how else to share it) -> I just signed up as a member.. and I think I can upload my files as a zip later. When I tidy them up..

To get the image to be in different directions (NESW), I copied and pasted the pixels and rotated them, without any special edits on the image. I'm not sure if it would have been more efficient to get the codes to rotate it in the game (instead of having the same pixel image drawn 4 times to get the 4 directions).

I also learnt that you need to right click the icons, choose "Edit State", and check the Movement state box, if the animation is meant to be played only when the mob is moving. So I had at least two 'icons'(?) in my dmi file with the same name, which was kept blank, but one would be used when the mob isn't moving and the other (with the M) is used when the mob moves.

Anyway, after that, I returned to the .dm file.. and typed something like this code below to assign my player's character to the dmi file I created.

mob
icon = 'topdownshooter.dmi'
step_size = 8


I also added other 'states' for this mob, which can be activated when the game is running by clicking certain verbs in one of the small windows (haven't really read how to make it change based on a keyboard action).

mob/verb/shoot()
icon_state = "Shoot"

mob/verb/guard()
icon_state = ""

mob/verb/crouch()
icon_state = "Crouch"



I think that was it for my first lesson (which I did a month or so ago, but only got to write it now).

So some things I still need to learn: (EDIT: "->" means I figured out the answers, or close to answers anyway)
- How do I assign a macro key to run a verb? -> explained in this tutorial at 9:45.. It's in the interface.
- Can I rotate my animation, say 10 degrees? Or is it 90, 180, 270 degrees only? -> See lesson 3 below
- How to set NPC mobs to a certain image, but not the player character. I read something about it - I just need to re-learn it cause I can't recall it now :p -> see this tutorial at 4:45
In response to Tsenses
Lesson 2: Procedural map generation

This was actually the reason I decided to make this log, because I had just got my head around understanding some codes. What I wanted to do is see how much I can fiddle with writing some code - and I found myself having an interest in creating algorithms that generate random maps to be generally fun, and there was a bit of material on the subject already available in the forums.

I'm basing my work on something created by Gughunter (http://www.byond.com/ forum/?post=39230&hl=archipelago%20generator). Thanks to his demos I got to understand a few more things about coding too.

I followed his idea of dropping a seed (LandBot), and moving that LandBot around whilst creating a path of land behind it.

The twist I tried to make was that instead of painting land onto the sea by 1x1 tiles; I'm instead trying to draw pieces of land in blocks of 3x3, making the masses of land look slightly more congruent.

Here's what I did. If anyone has an idea how to make it better, feel free to post below too. I know I may be making mistakes in using common naming conventions - and if anyone can pick those up too and point it out to me, that'd be nice (it's not necessary though - I don't really publish professionally anyway).

Anyway, I put this line first because I needed to use this T variable later on in more than one proc (I've read that declaring too many variables slows the machine down - but I haven't figured out how to avoid doing some of these). I also saw how Gughunter used #define instead. I believe that's a more proper way of doing it, but I haven't really gotten into that practice yet heh :p

var/turf/T  //global variable: T for turfs


I next get my world proc to call a MapGen proc (following Gughunter). This was something I couldn't have figured out without looking at how Gughunter did it. I didn't understand at first how to call procedures up. I guess world then New() was the one I needed to start everything. Or at least I had trouble figuring out how to name the first proc that would be called. Calling other procs within other procs wasn't too difficult after that.

EDIT: I watched some videos about using Unity.. and I guess this would be equivalent to something like "void Start()". So I guess "world New()" sorts of starts off the chain of calling up the procedures..

world
turf = /turf/water //Fill map with water tiles first (Don't think this works properly actually).. If I changed to fill with sand first, it didn't work as I thought.

New()
MapGen() //Initiates call on MapGen below (1)


.. My MapGen came next.. I used LandBot twice (I realise it's a crude way of doing it) so that I dropped the seeds that started drawing the pieces of land at possibly 2 random places. I was trying to get it to only run the second LandBot proc IF the total proportion of land to sea was below a certain percentage. But I haven't managed to do that yet. *Anyone know how?*. I meant to put other procs below LandBot in the future (such as a proc to make the borders of sea and land to be sand - like what Gughunter did). I haven't gotten that far in my self-study tutorial :p

world/proc/MapGen() //called from New() above (1); then calls LandBot procedure below (2)
LandBot()
LandBot()


..The LandBot proc itself comes next.. The formula looks pretty clunky because I had to make sure when my LandBot landed, it didn't start of too close to the sides of the map. Otherwise, my 3x3 block can't fit and nothing gets painted. In fact, I made it a bit variable in that I can adjust my brush size (BSize) above and make it 5x5 blocks or more.

What I did is drop the LandBot, move it, paint sea to land, move again, paint sea to land, move again, paint sea to land (repeated up to 7 times). It was either that, or drop the LandBot, paint sea to land, before making the first move.. but at the last cycle I would move and not paint. I was assuming it didn't make too much of a difference, so left it as it is below. (I also tried calling the CreateLand proc before I used for i<7 .. and the results looked similar)

world/proc/LandBot() //called by MapGen above (2); also calls CreateLand procedure below (3)
T = locate(rand(3,world.maxx-2), rand(3,world.maxy-2), 1) // throw LandBot down, without being too close to the side
var/i
for (i=0, i<7 , i++)
T = locate(min(world.maxx-1,max(2,T.x+rand(-1,1))),min(world.maxy-1,max(2,T.y+rand(-1,1))),1) // move LandBot from T's position, minding borders using max and min (formula too clunky?)
CreateLand() //this procedure turns water into land


.. Finally, my CreateLand proc looked for surrounding tiles and turned them into land if they were water. (or it was placing pieces of land on the water - with the water tiles still hidden beneath it *does that slow the machine down? How can I make it so that the water tile is replaced instead of merely overlapped?*). Anyway, it took me quite a while to find out that "in block" was probably what I needed, but I finally managed to get it right, and was quite glad I found it.

Oh yea, and looking at the codes below, I just realised I edited my brush size in this version to be random in nature. So it's not a fixed 3x3 brush I'm using to paint the tiles. It could be a 1x1 up to a 5x5 brush. I trialed and erred to come to the conclusion that the randomness of adding 3 random numbers ranging from 0 to 1 had a better distribution than 1 random number from 0 to 3 (I wanted the center of the distribution to occur more frequently).

world/proc/CreateLand() //called by LandBot above (3)
var/turf/S //S for surroundings
var/BSize //BSize for brush size
BSize = rand(0,1) + rand(0,1) + rand(0,1)
for (S in block(locate(T.x-BSize,T.y-BSize,1),locate(T.x+BSize,T.y+BSize,1)))
if (!istype(S, /turf/grass))
new /turf/grass(locate(S.x,S.y,1))


And that's about it.. so if I ran the whole thing.. It sorts of worked and gave me some land area over a piece of sea. What I haven't figured out:

1) How to make the LandBot create more land only if the ratio of land turfs to water turfs is below a certain percentage.

2) How best to go through each tile, and check if there was water around it, and convert it into sand. I saw Gughunter doing this, but I'm trying to see if I can make it so that I replace it with a tile that actually is half in water, half in land, and a slim line of beach in between.

3) How to make it so that the sides of the map is painted too. Something about my algorithm is making my LandBot avoid the sides more often than I like. Haven't gone through it again to see just why that is.

4) How to resize the map. I know this is probably a trivial matter for some of you :p But I can't actually get my map size to be different from the default I get. I tried putting two lines of codes at the beginning.. .. but somehow the only effect they had was make my "turf = turf/water" line work. The size doesn't change. -> Go to the Map Editor by double clicking the dmm file, then Edit > Set Map Size

maxx = 15
maxy = 15



Anyway, my whole codes after Tutorial 1 and 2 currently look something like this (combining all those pieces above together).

/*
These are simple defaults for your project.
*/


world
fps = 25 // 25 frames per second
icon_size = 32 // 32x32 icon size by default

// maxx = 15
// maxy = 15
view = 6 // show up to 6 tiles outward from center (13x13 view)


// Make objects move 8 pixels per tick when walking

var/turf/T //global variable: T for turfs

world
turf = /turf/water //Don't think this works..

New()
MapGen() //Initiates call on MapGen below (1)

world/proc/MapGen() //called from New() above (1); then calls LandBot procedure below (2)
LandBot()
LandBot()

world/proc/LandBot() //called by MapGen above (2); also calls CreateLand procedure below (3)
T = locate(rand(3,world.maxx-2), rand(3,world.maxy-2), 1) // throw LandBot down, without being too close to the side
// CreateLand()
var/i
for (i=0, i<7 , i++)
T = locate(min(world.maxx-1,max(2,T.x+rand(-1,1))),min(world.maxy-1,max(2,T.y+rand(-1,1))),1) // move LandBot from T's position, minding borders using max and min (inefficient?)
CreateLand() //this procedure turns water into land

world/proc/CreateLand() //called by LandBot above (3)
var/BSize //Brush size
var/turf/S //S for surroundings
BSize = rand(0,1) + rand(0,1) + rand(0,1)
for (S in block(locate(T.x-BSize,T.y-BSize,1),locate(T.x+BSize,T.y+BSize,1)))
if (!istype(S, /turf/grass))
new /turf/grass(locate(S.x,S.y,1))

mob
icon = 'topdownshooter.dmi'
step_size = 8

obj
step_size = 8

turf/grass
icon = 'floor.dmi'
icon_state = "grass"

turf/water
icon = 'floor.dmi'
icon_state = "water"

turf/coast
icon = 'floor.dmi'
icon_state = "coast"

turf/corner
icon = 'floor.dmi'
icon_state = "corner"

mob/verb/shoot()
icon_state = "Shoot"

mob/verb/guard()
icon_state = ""

mob/verb/crouch()
icon_state = "Crouch"

area
icon = 'floor.dmi'
In response to Tsenses
Lesson 3: Rotating stuff

I didn't have a lot of time this weekend to look at a lot of things - but I think I managed to figure out a few things. I know I'm at a very noob level, so hope anyone reading this bears with me..

i) I learnt how to get the player to provide the value to rotate my icon
ii) I put into practice how vars belonging to mobs are used. (and also how to use .usr)
iii) I followed the "turn proc (applied to an icon)" in http://www.byond.com/docs/ref/index.html to find out how to turn the pixels after all. But the pixels do get distorted badly quite a lot if I turn it too many times. I think I can reduce this effect if I set it back to 0 degrees before turning it again.

So I did something like this

mob
icon = 'topdownshooter.dmi'
var/angle = 0 //added this new variable to store the angle at which my mob is facing, (the value is 'retrieved' by usr.angle below)
step_size = 8

mob/verb/rotate(n as num) //"n as num" lets the user type a variable; 'input' command seems to allow user input as well
usr.icon = turn(usr.icon,-usr.angle) //this returns the icon back to its original orientation (drop this line if the angle is meant to be incremental)
usr.icon = turn(usr.icon,n) //before turning to the desired angle
usr.angle = n //store the new angle into the mob's 'angle' variable


That's about time I have today. I meant to try and change some of my land turfs into coast turfs, and rotate them to face the sea. Haven't really figured how exactly to do that in an optimal way.. I guess I'll do that next weekend.

EDIT (after a week):
So I spent some time looking at this again.. And thought this might be an alternative way of setting up what I did above.. (After reading on using "icon" in http://www.byond.com/docs/ref/)

mob/verb/rotate(n as num)                //"n as num" lets the user type a variable; 'input' command seems to allow user input as well
var/icon/I = new('topdownshooter.dmi') //create a new var called "I" as an icon type.
I.Blend(rgb(40,0,0)) //place a red tint over it (just to test)
usr.icon = I //replace icon with the new icon called I above
// usr.icon = turn(usr.icon,-usr.angle) //commented out, this returns the icon back to its original orientation (drop this line if the angle is meant to be incremental)
usr.icon = turn(usr.icon,n) //before turning to the desired angle
usr.angle = n //store the new angle into the mob's 'angle' variable



Pros: The pixels don't get distorted if I turned it several times (my earlier version did)
Cons: According to the DM reference, this might cause some overheads and slow down processing more than I like.. hmm
I'm also a complete neophyte slowly (work is ramping up yet again -- halp!) immersing myself into DM, and I wanted to let you know that I enjoy and appreciate your efforts. It's very engaging!
In response to PixelScientist
Hey thanks for replying too :p Was kinda getting a bit lonely here lol (although I mentioned in the first post that I don't expect anyone to really read, and I didn't even put a TL; DR post at the end of my posts. )

Anyway, I meant to tell myself to get more of my doctorate thesis written up this week, or else I can't reward myself with time to look at hobbies like BYOND.. and uhm.. I didn't really write as much as I liked, so I guess I shouldn't spend too much time in BYOND for this weekend heh..

But I did remember which tutorial I was watching (I know there's way too many - but this one was highlighted at the front page cause it's new I suppose, and it's quite nice to follow I thought. BYOND tutorials by Dante Ferris. I watched them some time ago, and he's still uploading new ones I believe - with one I saw about creating user interfaces (I wanna watch that soon :p).. but what I remember among the things he shared were:
.. How to append stuff like a health bar on the top of your character (I saw that people do that to append hair color, shirt color etc to characters.. looks pretty handy, although I read that the overlays don't work properly sometimes).
.. How to do short, one-off clips of animations like punching, then revert back to your original icon state.

And I'm sure there's still quite a bit in that. I just haven't had time to take notes and practise them heh. One of these days... (obviously I'm not cut out to be a pro programmer at this rate heh.. hopefully anyone who aspires to be one doesn't do what I do)
In response to Tsenses
Tsenses wrote:

.. How to do short, one-off clips of animations like punching, then revert back to your original icon state.

mob
verb
kick()
//do stuff
flick("kick", usr) //look up flick in the reference for more information


In response to Rickoshay
Ahh.. flick.. that was it.. thanks.. saved me having to go back to the video :p (was planning to do that)

EDIT:
Other stuff I've been reading and found interesting (actually everything looks interesting here, but I only have so much time to read and type it in my journal :p)
.. Cool map generation by Lummox Jr
.. Some really condensed style of coding.. It looks like Morse code or some kind of encrypted language :p
Going back over the map generation for Incursion got me to thinking, and I ended up stumbling across this article that blew my mind. I'm toying with the idea of trying to adapt the concept to redo Incursion, because frankly I've always been fascinated with the Voronoi tesselation and it'd be awesome to have more organic shapes--even more awesome if I could also get cool river and terrain shading out of it.

And if you think that condensed code is something, download the source for Runt or Scream of the Stickster: both of them made for 4K challenges.
In response to Lummox JR
I cant type anymore now.. because my mind has been blown too..

walking zombie here..
In response to Tsenses
I was thinking what I should fiddle with this weekend - and decided I'll try and figure out if I can look at mouse controls.

So what I'll try to learn to do these couple of days perhaps is to see if I can click somewhere on a map, and get my player character to turn towards it. Which I suppose means I need to learn:

i) How to detect where was clicked
-> I think it's under client/Click? (trying to read the the developer references under mouse control.

ii) How to calculate the angle between my player character and the place I clicked
-> I guess I'll need to remember some trigonometry? (or is there an easier way heh)

iii) Rotate the player character
-> I guess this should be easy given I've managed to rotate the character above.

Right.. so here starts my BYOND journey this weekend (and I probably won't finish by tomorrow lol)..
Just a quick little detail:

Interesting to read this, actually! But I would like to bring your attention to usr vs src.

In short, it is important once things start getting bigger to be using src unless you know you should be using usr specifically. I would go into the hows and whys, but some people have already done so-- much more effectively than I ever could. Here's a quick article to read that explains it in short.

http://www.byond.com/forum/?post=1789464&hl=src&hla=Xirre
In response to Decius Reln
Ahh.. these were the exact feedback I was hoping for. I'm quite sure I'll be making noobish mistakes here and there.. So thanks for pointing them out and pointing me in the right direction to read up more about it. It really helps because I find there's so much information I need to learn and some direction certainly helps where to get going hehe..

Thanks again for the link - very much appreciated.

Edit: So I changed all the usr to src.. and everything still works as before.. I'm thinking this is to do with "subject verb object" of a sentence? So usr is the subject, src is the object?

So while I had "Make the player character rotate himself", I couldn't tell the difference because src and usr were both the player character. So in my earlier example, I couldn't write "Make the player rotate something else", unless I used src as I've been corrected to do. That makes sense now :p
In response to Tsenses
Minor aside before I start my next lesson. Ter13's Sunday snippets are a fun read !

Lesson 4: Using Click

So, after some procrastination yesterday, I'm trying to get down to looking at how to use Click. I went to the Developer reference first, then went to 'client' on the left menu, and to the 'Click' link.

My first noobish mistake: I thought the example in the video said 0 (zero) instead of O (capital o), and just spent my last 5 mins trying to figure that out :P ..

Anyway, since I've figured that out, now I'll examine this example code from the references page.. and play around with it

client
Click(O)
usr << "You clicked [O]"
..() // do default action


Noob questions I need to figure out for this lesson:
1. What the O is for?
2. Why "..()" is required in the example?
3. Should I even use client/Click ? Or just 'something'/Click ?

Hmm.. I'll stick with 3 questions for now, and add more later perhaps..

1. What the O is for?
-> I changed both O's to X's, and it obviously still works. So yea, noobish lesson here : O is just a name of the parameter I provide, and I can call it anything.

Tried to compile and the run the game, and I get messages of "You clicked the water" or "You clicked the grass". So, I suppose this must be returning the object I'm clicking. That works fine for me.

So I checked the reference again, and realised it said click had 4 : Click(object,location,control,params)

To experiment what those are, I just tweaked it to be:

client
Click(X, Y, Z, A, B)
usr << "object is [X] \n location is [Y] \n control is [Z] \n params is [A] \n nothing is [B]"
..() // do default action


Note: I only recently learnt "\n" is for a new line - see how noob I am :p

But anyway, I got these results when I ran the game and tried clicking stuff.

"
object is the water
location is the water
control is mapwindow.map
params is icon-x=9;icon-y=21;left=1;screen-loc=9:25,12:29
nothing is
"

or

"
object is the grass
location is the grass
control is mapwindow.map
params is icon-x=19;icon-y=31;left=1;screen-loc=12:11,11:7
nothing is
"

So.. what's the difference between object and location again? :p .. Guess I'll figure that out next time.
-> Further experimentation:
If I clicked my player character, I get:
"object is Guest-2714902485
location is the water
control is mapwindow.map
params is icon-x=12;icon-y=29;left=1;screen-loc=7:12,7:29
nothing is
"
.. in the console. So I suppose object is what I clicked on, and location is what turf I'm standing on?

I could use this: For params, icon-x=12;icon-y=29 seems to be the pixel I'm clicking, with the bottom left being pixel 0,0. That seems to be what I need to get my character to turn towards later.


2. Why "..()" is required in the example?
-> I tried deleting that line - and can't note a difference yet. Need more exploring.

3. Should I even use client/Click ? Or just 'something'/Click ?
I read "Click proc (atom)" first. So I tried changing the 'client' in the codes above to 'turf'. And it seems I only get something logged to the console when I click turfs, but nothing happens if I click my player character.

Similarly, if I changed 'client' to 'mob' instead, The procedure only works if I clicked my player character, but nothing happens when I click turfs.

One main difference is that there are only 3 arguments I need to put in, instead of 4 under client. Subtle difference I suppose.

********

Anyway, now that I've roughly tried to answer my 3 questions (and haven't figured out newer questions), let me try to see if I can get my player character to turn towards where I click. Yea, I guess I'll need something to figure out where my player character is currently at. Let's see now...
Whenever you click something, client/Click() is called. It's a built-in verb. By default, it will see if you clicked on an atom, and if so it will call that atom's Click() proc. So if, say, you only want to respond to clicks on mailbox objects, you would write a proc for obj/mailbox/Click().

Other mouse procs do this same thing, finding which atom you're interacting with and calling a proc.

If you do override client/Click(), the reason you might call ..() is to use the default behavior. (You don't need to include the same arguments when you call ..()--they're included automatically.) So if you wanted to, say, output a message every time a player clicked, you might override client/Click() to do so, and then you'd call ..() to make sure the click was handled normally.

By the way: Even though something like obj/Click() is technically a proc, usr is usually valid there--because typically, these procs are only ever called by verbs such as client/Click(). Hence I call them pseudo-verbs.
In response to Lummox JR
Oh. So, if I typed something in my codes under client/Click() = I'm altering the default way that clicks are handled.

But if I typed those same codes under, say obj/mailbox/Click() = I'm only altering the way clicks are handled when mailboxes are clicked.

That makes sense now. Thanks! :)

Will need more time to figure out the pseudo verb thing though - sounds a bit philosophical :p


Anyway, the log below is after a bit more experimentation, and I'll just call this a new 'lesson' since it doesn't really deal with clicking.


Lesson 5: Calling procedures

Well, I've had some lessons about calling using world/New() to call MapGen(), which calls LandBot() etc in lesson 2 above. But I think I'm learning a few other things today (well, I haven't actually figured out a lot of things lol)


But I was trying to get my codes to tell me the angle between where I've clicked, and where my player character is currently at. Here's what I have so far:

I found out that there wasn't built-in trigonometry functions beyond sin and cos, but a Google search of "Byond trigonometry" nicely led me to this nice little post http://www.byond.com/developer/Oasiscircle/Trigonometry.

And then with a bit of guessing that usr.x and src.x returned the x locations of the usr (player character) and the src (where I've clicked) [and usr.y for y].. I tried this:

turf/Click()
usr << Angle()

turf/proc/Angle() return arctan((src.y-usr.y)/(src.x-usr.x))

proc/arctan(n) return arccos(1 / sqrt(1+n*n)) //from http://www.byond.com/developer/Oasiscircle/Trigonometry


Well, a bunch of issues with this:
1. I think I need to have turf/proc/Angle() instead of proc/Angle(), otherwise 'src' or wouldn't work..

2. If I set turf/proc, I can only call it in the Click() if I have turf/Click().. I couldn't get it to work with mob/Click() or anything else (do I need to somehow expose the procedure to it?)
-> Thanks to Lummox's explanation below. So if I wanted turf and mob to both be able to use my customised Click procedure, I would need to write "atom/Click()" instead of mob/ or turf/ .. Now I get it !

3. The angles calculated range from 0 to 90.. whereas I'm trying to get it to tell me 0 to 360..

4. Oh, and it can't calculate if the rise over the run is 0/0.. do I need to use a bunch of IF functions? I totally forgot most of my trigonometry rules :p

5. How do I get it to check the pixel position instead of game tiles? Or perhaps using pixel_x might be a bit more accurate..

6. Haven't figured out how to link my rotate part and this part together heh.. I was trying to get the Click to call my rotate verb from Lesson 3 above.. and I think I got it to work a bit if I changed verb to proc, i.e. mob/verb/rotate to mob/proc/rotate instead.. but it would sort of only work if I didn't have mob and turf conflicting.

Hmm.. a lot more to learn heh
In response to Tsenses
Tsenses wrote:
turf/Click()
usr << Angle()

turf/proc/Angle() return arctan((src.y-usr.y)/(src.x-usr.x))

proc/arctan(n) return arccos(1 / sqrt(1+n*n)) //from http://www.byond.com/developer/Oasiscircle/Trigonometry
Well, a bunch of issues with this:
1. I think I need to have turf/proc/Angle() instead of proc/Angle(), otherwise 'src' or wouldn't work..

Yes, that's correct--because in turf/Click(), src is the turf you clicked. When you call Angle(), unless it's a global proc it get called as src.Angle().

However, right off the bat you have a problem: You should not be using usr in the Angle() proc. It's bad practice to use the usr var in procs. I would suggest actually that Angle() be defined either as a global proc, or as an atom proc, and you send it the args you need.

// version 1: global proc
proc/Angle(atom/A, atom/B)
// angle from A to B
...

// version 2: atom proc
atom/proc/AngleFrom(atom/ref)
// angle from ref to src
...

The global Angle(A,B) is equivalent to B.AngleFrom(A).

2. If I set turf/proc, I can only call it in the Click() if I have turf/Click().. I couldn't get it to work with mob/Click() or anything else (do I need to somehow expose the procedure to it?)

That's why it'd be better to make it an atom proc (where it would belong to turfs and mobs alike), or global. Every object inherits procs and vars from its parent type. Turfs and mobs are both descended from atom. The hierarchy is like so:
datum
atom
turf
area
movable
obj
mob

3. The angles calculated range from 0 to 90.. whereas I'm trying to get it to tell me 0 to 360..

arctan() on its own will only ever range from -90° to 90°. What you need is a specialized proc, which I've written.

Now me, I prefer to deal with angles in a nautical format, where 0=north and it goes clockwise. If you use the mathematical convention where 0=east and it goes counterclockwise, the code would differ. Here's an atan2() snippet using the latter:

proc/atan2(dx, dy)
// special case: vertical or no difference
if(!dx) return (dy>0) ? 90 : ((dy<0) ? -90 : 0)
// . is the default return value
. = arctan(dy/dx)
if(dx < 0) . = 180 - .
if(. < 0) . += 360

Therefore the angle from A to B would be atan2(B.x-A.x, B.y-A.y).

4. Oh, and it can't calculate if the rise over the run is 0/0.. do I need to use a bunch of IF functions? I totally forgot most of my trigonometry rules :p

Yep. You definitely need to handle division by 0 cases.

5. How do I get it to check the pixel position instead of game tiles? Or perhaps using pixel_x might be a bit more accurate..

If you're using pixel movement--that is, if you don't rely on gliding behavior and mobs have step_size defined--then you would use step_x and step_y in your calculations. Specifically:

// this assumes 32x32 icon size
#define centerx(A) (A.x * 32 + A.step_x + A.bound_x + A.bound_width/2)
#define centery(A) (A.y * 32 + A.step_y + A.bound_y + A.bound_height/2)
It occurs to me that it would've probably been polite to ask you if you would dislike me doing a sort of log alongside yours before I started it. Just got excited at the idea once I had started seeing you actually getting feedback. I think it'd be cool if more people did it-- And would help encourage me to keep up.

Anyway: I do like this. That's helping guide me a bit in the fact that I was wondering if I could create a randomly generated world well-- I think that I could work on doing that and then work on saving worlds. But I'm not ready for something quite that complicated; for now, I'll be content just getting a world together in the first place.

As for you: thanks for posting this! Really. It is encouraging me, and it can be nerve wracking to put up some code for review.
I think it's great that both of you are doing this. It shows activity and positive progress. Don't be put off by the folks that are jumping in and derailing.

By the way, there's a new feature that makes it so that you can't see the posts of people you have pagerbanned and any replies to that person's post. It's actually really awesome, and it's allowed me to make this community a much more positive experience.
In response to Aero Sye
Aero Sye wrote:
It occurs to me that it would've probably been polite to ask you if you would dislike me doing a sort of log alongside yours before I started it. Just got excited at the idea once I had started seeing you actually getting feedback. I think it'd be cool if more people did it-- And would help encourage me to keep up.


I didn't mind at all :D Only thing was that I was confused for a while when I clicked into your thread (thinking it was mine), and was wondering when I wrote those stuff. Kinda creeped me out a while till I came to my senses :p

p.s. Thanks to Lummox and Ter for the encouragement and replies too - I'll go through them over the weekend :D
Page: 1 2