ID:1951751
 
(See the best response by Kaiochao.)
Problem description:



We have Bob.

Bob wants to find his enemies, though they're off screen. To assist Bob, I would like arrows pointing in their direction along with the arrows' screen_loc based on the directional orientation.

The arrows, I can turn. My only problem thus far is properly moving the arrow. What sort of formula would I use to adjust the offsets?

Help me help Bob!

Edit: Bob is happy!
Best response
Off the top of my head:
// library used: Kaiochao.AbsolutePositions
#include <kaiochao/absolutepositions/absolute positions/absolute positions.dme>

mob
proc/PointArrow(obj/Arrow, atom/Target, MinDistance)
// src: the player seeing the arrow
// Arrow: the arrow object in your HUD
// Target: where you want the arrow to point
// MinDistance: pixels before Target is considered "off screen"

// default to slightly less than half the smallest size of the viewport
if(isnull(MinDistance))
MinDistance = min(client.bound_width, client.bound_height) * (3/8)

// a vector (difference in positions) from src to Target, in pixels
var dx = Target.Cx() - Cx()
var dy = Target.Cy() - Cy()

// the square magnitude of the vector
var dot = dx*dx + dy*dy

// the target is too close, hide the arrow and stop the proc
if(dot < MinDistance * MinDistance)
Arrow.screen_loc = null
return

// the target is far enough away at this point

// get the angle to the target using atan2
var angle = dx > 0 ? arccos(dy / sqrt(dot)) : -arccos(dy / sqrt(dot))

// position the arrow in the center of the screen (will be offset by transform)
Arrow.screen_loc = "CENTER"

// start setting up the arrow's transform
// imagine a clock
// you start in the center
// Translate(0, MinDistance) moves you straight up to the 12
// Turn(angle) turns you clockwise to the angle, along the curved edge of the clock
var matrix/m = new
m.Translate(0, MinDistance)
m.Turn(angle)
Arrow.transform = m

// and we're done

All you have to do is add an obj with the arrow's appearance to client.screen and call this proc whenever you want to update it. For example:
#include <kaiochao/shapes/shapes.dme>

world
maxx = 50
maxy = 50
fps = 60

turf
icon_state = "rect"
New() color = x % 2 == y % 2 ? "silver" : "gray"

obj/arrow
icon_state = "arrow"
color = "red"

mob
icon_state = "oval"
color = "blue"
step_size = 4
var target_arrows[]

Login()
..()
new /mob/enemy (locate(10, 10, 1))

verb/remove_target(mob/m in target_arrows)
client.screen -= target_arrows[m]
target_arrows -= m
if(!target_arrows.len)
target_arrows = null

mob/enemy
color = "red"

verb/add_target()
set src in oview()
if(src in usr.target_arrows)
return
if(!usr.target_arrows)
usr.target_arrows = new
usr.target_arrows[src] = new /obj/arrow
usr.client.screen += usr.target_arrows[src]

// update the arrow every frame
while(usr && (src in usr.target_arrows))
usr.PointArrow(usr.target_arrows[src], src)
sleep world.tick_lag

You could even add to this demo a verb on the arrow that removes the target, but I've probably done enough already.
In response to Kaiochao
if(isnull(MinDistance))
MinDistance = min(client.bound_width, client.bound_height) * (3/8)


Where are you pulling the client's bound width and height variables from? They aren't native to .dm
In response to Bl4ck Adam
They're new to 509, which is in beta. There are other ways to get this information, though.
// I already made a library that includes it
#include <kaiochao/mapinfo/map info/map info.dme>

// client.bound_width == client.ViewPixelWidth()
// client.bound_height == client.ViewPixelHeight()
I went ahead and updated to the beta. The arrows work like a charm. Thanks!
In response to Bl4ck Adam
Should I make this a library...? It's kind of simplistic, especially if you remove all the comments.
I don't see why not. Many a game could probably use something of the sort, be it a quest tracker or anything they can think of in that case.
There was a really old library that would put arrows on the edge of the map/view and you could move with those. I wasn't able to track it down though (it is really old and I don't remember what it was called).

Seems like kaio got it handled for you, though! :)
In response to AERProductions
AERProductions wrote:
There was a really old library that would put arrows on the edge of the map/view and you could move with those. I wasn't able to track it down though (it is really old and I don't remember what it was called).

Seems like kaio got it handled for you, though! :)

This is what you're talking about!
In response to Bl4ck Adam
Yes it is, thanks for reminding me!
That is what I was going to suggest, but it probably isn't optimal. :)
In response to Bl4ck Adam
Bl4ck Adam wrote:
AERProductions wrote:
There was a really old library that would put arrows on the edge of the map/view and you could move with those. I wasn't able to track it down though (it is really old and I don't remember what it was called).

Seems like kaio got it handled for you, though! :)

This is what you're talking about!

Wow, I forgot all about that, it's from twelve years ago. Not what they were looking for though.
In response to Kaiochao
Kaiochao wrote:
Should I make this a library...? It's kind of simplistic, especially if you remove all the comments.


Please do. I can see myself wanting this somewhere down the line
In response to Flick
The magical things the years do, eh flick?

I remember messing around with that library all those years ago on a certain, unreleased project which was my first attempt at a game on byond. Still have the design docs for that project, but not the original source (lost to hdd damage).
Here's the library. It's a bit updated and easier to include, compared to what's in the forum post.

http://www.byond.com/developer/Kaiochao/ScreenArrows
In response to Kaiochao
Kaiochao wrote:
Here's the library. It's a bit updated and easier to include, compared to what's in the forum post.

http://www.byond.com/developer/Kaiochao/ScreenArrows

It looks a lot nicer both in game and code itself. You're the best!