0

Basically I have a grid of spans resembling a chess/checker board with players & ai taking turns moving.

During a players turn, they can "shoot" other players, however I'm having a hard time getting my head around how to tell if there is someone in the crossfire.

I consider a "chess piece" occupying a square as taking up the entire square, so really just need a way to find out if the "bullet" passes through a square as it travels from point a to point b.

Here is a brief example: http://jsfiddle.net/hnxs4cvq/9/

javascript/jquery:

$(window).load(function(){
$(function () {
    $('.skillRangeSquare').click(function () {alert('hit!');})
}) 
});

html:

  <span id="1" class="battlefieldSquare_Base battlefieldSquare_B " name="r1c1"> &nbsp;</span>
<span id="2" class="battlefieldSquare_Base battlefieldSquare_A  skillRangeSquare" name="r1c2">monster</span>
<span id="3" class="battlefieldSquare_Base battlefieldSquare_B " name="r1c3"> &nbsp;</span>
<span id="4" class="battlefieldSquare_Base battlefieldSquare_A " name="r1c4"> &nbsp;</span>
<span id="5" class="battlefieldSquare_Base battlefieldSquare_B " name="r1c5"> &nbsp;</span>
<br>
<span id="11" class="battlefieldSquare_Base battlefieldSquare_A " name="r2c1"> &nbsp;</span>
<span id="12" class="battlefieldSquare_Base battlefieldSquare_B " name="r2c2"> &nbsp;</span>
<span id="13" class="battlefieldSquare_Base battlefieldSquare_A " name="r2c3"> &nbsp;</span>
<span id="14" class="battlefieldSquare_Base battlefieldSquare_B " name="r2c4"> &nbsp;</span>
<span id="15" class="battlefieldSquare_Base battlefieldSquare_A " name="r2c5"> &nbsp;</span>
    <br>
<span id="21" class="battlefieldSquare_Base battlefieldSquare_B " name="r3c1"> &nbsp;</span>
<span id="22" class="battlefieldSquare_Base battlefieldSquare_A skillRangeSquare" name="r3c2"> monster</span>
<span id="23" class="battlefieldSquare_Base battlefieldSquare_B" name="r3c3"> &nbsp;</span>
<span id="24" class="battlefieldSquare_Base battlefieldSquare_A " name="r3c4">&nbsp; </span>
<span id="25" class="battlefieldSquare_Base battlefieldSquare_B " name="r3c5"> &nbsp;</span>
        <br>
<span id="31" class="battlefieldSquare_Base battlefieldSquare_A " name="r4c1"> &nbsp;</span>
<span id="32" class="battlefieldSquare_Base battlefieldSquare_B " name="r4c2"> &nbsp;</span>
<span id="33" class="battlefieldSquare_Base battlefieldSquare_A " name="r4c3">player </span>
<span id="34" class="battlefieldSquare_Base battlefieldSquare_B" name="r4c4"> &nbsp;</span>
<span id="35" class="battlefieldSquare_Base battlefieldSquare_A " name="r4c5"> &nbsp;</span>

The monster closest to the player is ok to hit, there is nothing in the way, however the one further back is "blocked" by the closer one since the projectile would pass through the upper corner of the square it occupies.

I'm looking for a way, in the onclick, to determine that.

Edit: I should have mentioned the projectile would be going from center square to center square.

msimmons
  • 146
  • 1
  • 3
  • 15
  • 1
    What is the aiming resolution? In other words, can a bullet travel from anything other than centre-of-square to centre-of-square? – Roamer-1888 Oct 13 '14 at 00:05
  • without something a little more substantive than `alert` it sure seems you are far too early to be posting questions yet. Nobody here is going to do the heavy developing for you – charlietfl Oct 13 '14 at 00:08
  • @ charlietfl - I have about a thousand lines of javascript alone for handling movement, turns, skills, etc. I didn't think it would be complimentary to the question to include anything more than I have. – msimmons Oct 13 '14 at 00:15
  • @Roamer-1888 - Sorry, I should have mentioned that, from center square to center square. – msimmons Oct 13 '14 at 00:18
  • 1
    you would use the slope formula, and then determine if each square (cropped by peices opposite corners) is an intersect of the slope – dandavis Oct 13 '14 at 00:19
  • @dandavis - I think I understand partially. I believe I would want to get the x/y of the center of each span and "draw a line" between the two, however I'm not sure how I would determine the intercept. – msimmons Oct 13 '14 at 00:26
  • 1
    "slope intercept" is a math thing, i still have nightmares about it from junior high... – dandavis Oct 13 '14 at 00:26
  • 1
    I ain't gonna code it for you but I'll give you some clues. Approach 1: [Perpendicular Distance from a Point to a Line](http://www.intmath.com/plane-analytic-geometry/perpendicular-distance-point-line.php) Approach 2: [Intersection of line and square](http://stackoverflow.com/questions/4551008/intersection-of-line-and-square-in-java). Personally, I would code both then assess which gives the right sense of justice when playing the game. – Roamer-1888 Oct 13 '14 at 00:29
  • @dandavis - I guess what I meant to ask was, how do I make this line aware of these spans? – msimmons Oct 13 '14 at 00:29
  • 2
    you don't. you want to use pure js, no dom. if you do math on the size of the spans, your results could vary across devices (yikes!). you run the calc on a model of the board or sub-board, and then apply the results to the spans. an array of arrays is one way, but you really don't even need a 2d model, you can just calc isIntercept(x,y) for each relative coord... – dandavis Oct 13 '14 at 00:31
  • @Roamer-1888 - Thanks, I think I'm starting to understand it better! – msimmons Oct 13 '14 at 00:32
  • @dandavis - ooh! Totally sorted me out there, I think. I should create the board as a 2d array, perform the slope intercept on that, then bam! Thanks! – msimmons Oct 13 '14 at 00:34
  • @msimmons, think of the game as something played primarily in javascript, that "just happens to have" a visual representation (DOM elements). – Roamer-1888 Oct 13 '14 at 00:59
  • @Roamer-1888 - Makes sense. I'm updating my fiddle a bit, based on some of the code in this article: https://dev.opera.com/articles/3d-games-with-canvas-and-raycasting-part-1/ It's one that I felt was way more than I needed, and now that I understand what I need better, I can pick and choose from it. – msimmons Oct 13 '14 at 01:13
  • 1
    To avoid the hard math, you *may* be able to use something like [Playful.js](http://www.playfuljs.com/a-first-person-engine-in-265-lines/). You wouldn't need its full capability for 3D image rendering but you could use its ray-casting capability to model bullets. – Roamer-1888 Oct 13 '14 at 01:37
  • @Roamer-1888 - cool, I'll check that out! Part of my goal here is just to learn though. I've been a dev for well over a decade and it's generally "boring" stuff, "game" development is pulling me out of that shell a bit. – msimmons Oct 13 '14 at 02:12
  • @Roamer-1888 - I believe I have it working, I've edited the fiddle. I know it needs some adjustments, like not counting the player, or the target, I'll deal with those items later. Thanks again! – msimmons Oct 13 '14 at 03:01
  • @dandavis - I believe I have it working, I've edited the fiddle. I know it needs some adjustments, like not counting the player, or the target, I'll deal with those items later. Thanks again! – msimmons Oct 13 '14 at 03:02
  • 1
    @msimmons, what you have written is certainly on the right lines, but not a complete solution. You need to (a) cater for player and target in same column, where m will be infinite (b) travel in the right direction from player to target (x-- vs x++) (c) cater for shallow slopes where there may be more than one intersecting cell per iteration of the loop. – Roamer-1888 Oct 13 '14 at 07:50
  • 1
    You also need to properly cater for "corner grazing". Either both or neither corner-grazed cells should be detected. Personally, I would say that a corner-graze is a miss - neither of the grazers should be detected. I think you will find that the current algorithm will detect one grazer and not the other. – Roamer-1888 Oct 13 '14 at 08:02
  • 1
    These are all reasons why this problem is only superficially trivial. – Roamer-1888 Oct 13 '14 at 08:05
  • @Roamer-1888 - I actually have those on my to do list already and I'm fairly confident I can figure those out. Thanks again! – msimmons Oct 13 '14 at 14:38
  • 1
    Good luck - I'd be interested to know how you get on. – Roamer-1888 Oct 13 '14 at 15:48

3 Answers3

2

Hmm, it appears that the bullet passes through the corner shared by the squares (2,3), (3,2), (2,4) and (3,4), if (0,0) is the bottom left most square. Does that count as an obstacle?

Anyway I posted an extremely bad explanation before. I'll rewrite that coherently again here:

I created a diagram to here for visual aid:

https://www.desmos.com/calculator/zm8mayncqi

You know the path of the bullet travels through the columns two and three, so create a function and determine all obstacles in column (other than the player, and target). We have a monster at (2,3) which could potentially be in the way.

Next we find the equation as rupp has described, as represented by the blue line.

If the gradient is negative, we want the opposite (positive) of the equation of the diagonal of the obstacle square, and vice versa.

That, is we want the red dotted line which has a positive gradient.

We use simultaneous equations to determine if the two intersect.

If our two equations are: y=m1*x+c1 y=m2*x+c2

Then we can determine the x-coordinate by this: x=(c1-c2)/(m2-m1)

Now the equation of the bullet only exists between the pixels 105px and 175px horizontally,

So if 105 <= x <= 175 then we know that there is an intersection and thus an obstacle blocking the way.

Hope that helps?

Flying Emu
  • 430
  • 6
  • 14
1

you need to use the equation of the line. This is more a Math problem than a programming problem. But is pretty easy:

  • Find the equation for the shoot (line) from the player to the monster
  • Find if any of the obstacles lie within this equation -the points belong to the line-

How to find the equation for the line? You can google it, take a look at http://www.webmath.com/equline1.html

In general, a line is defined by an equation

y=mx+b

where "m" is the slope and "b" is an offset. You need to calculate "m" and "b". You can find the equation for a line if you know two points, that you do: the player and the target monster. We'll asume the player is at (x1,y1) and the monster at (x2,y2). So let's calculate m and b like this:

m = (y2 - y1) / (x2 - x1)

and to calculate b, you can use any point you already know.

So, returning to y= m*x + b, we know m:

Y = (y2 - y1) / (x2 - x1) * X + b

and in your case, imagine we shoot from the player, that is at (2,1) to the monster at (1,4), assuming (0,0) is the bottom corner:

  • we have m=(4-1) / (1-2) = 3/(-1) = -3
  • to calculate b, we use any point we already know such as the player at 2,1 => --> y=mx+b=-3x+b --> 1 = -3*2 + b --> b= 1 + 6 = 7

  • You now have the equation for this particular shoot, that is

    y=-3x+7

  • Now is trivial to know if any monsters lie within this line, just substitute the x and y and see if the equation works. To do this, substitute a monster's x and check the Y you have is the monster's Y. If this is the case, the monster will be in the middle.

  • The obvious problem is the accuracy or resolution. As you work with integer numbers, you have to define how the "line" will connect points. When you check if a monster is in the middle, you use the line equation you calculated previously, and check for a monster's X, the difference between the Y you get and the Monster's Y is less than 1. The lesser than +-1, the closest the bullet is: 0 would be a direct hit, +-0.25 a pretty direct hit, +-0.50 you'd maybe hit a leg, while +-0.80 the bullet would barely hurt it. Over +-1, the monster won't be hit.

rupps
  • 9,712
  • 4
  • 55
  • 95
  • 1
    "Now is trivial to know if any monsters lie within this line" - unfortunately no, it's not trivial. – Roamer-1888 Oct 13 '14 at 00:51
  • 1
    Well, triviality depends on ability. In my judgement, most folks won't find this trivial. – Roamer-1888 Oct 13 '14 at 01:13
  • 1
    you are welcome to edit and improve the answer, but i mean, it's high school maths :D – rupps Oct 13 '14 at 01:26
  • 1
    The reason why I'd say it's not high school maths is that not only must you detect intersections but in the case of multiple intersections, you need to determine which is the first intersection in the direction of travel of the bullet. And it needs to be coded efficiently. All the component parts are trivial but is the entirety? Try coding it an see if you still have the same opinion. – Roamer-1888 Oct 13 '14 at 01:45
  • 1
    yes of course things will get complicated, I just tried to introduce the equation to detect if an element intersect the trajectory. Once you know how to do that, you start taking into account things like the one you point, but you have to start somewhere! Any complex project is just a group of trivial parts! And about efficiency, once you write something that works, then you optimize it. There are no magic recipes as you sure know. – rupps Oct 13 '14 at 01:50
  • 1
    OK, I think we agree more than disagree. – Roamer-1888 Oct 13 '14 at 01:54
  • @rupps - I dropped out of high school over 20 years ago (fortunately this is the first time I've needed "complex" math since then) :p Your link is really helping and so far I have the code calculating "m" (I updated the fiddle to allow you to click on any square and get "m" in relation to the player). I'll deal with "b" and detecting any "line of sight" blocking tomorrow. Also, regarding accuracy I count the whole square as a "hit", for my purpose it is done by "dice roll" (ie. D&D armor class vs THAC0), they could miss based on chance, I just got stuck on if they can even see the square. – msimmons Oct 13 '14 at 01:56
  • Being a current highschool student, I know it requires year 7 mathematics, so yes it is highschool maths. – Flying Emu Oct 13 '14 at 01:58
  • Probably a dumb question but (having trouble getting from equation to javascript... ) to get "b" does "b=y-mx" work? – msimmons Oct 13 '14 at 02:21
  • @rupps - I believe I have it working, I've edited the fiddle. I know it needs some adjustments, like not counting the player, or the target, I'll deal with those items later. Thanks again! – msimmons Oct 13 '14 at 03:01
  • 1
    cool!! I've fiddled a little, and prepared this for you, hope yo like it! http://jsfiddle.net/57p12h55/1/ – rupps Oct 13 '14 at 03:01
  • @rupps - Very cool! I'm definitely going to reuse parts of that as a "hover" for movement. I'm not sure I agree with some of the collision, or lack thereof however. For example, if you click the lower left corner, I think the bullet should travel through 4 squares (if we count the player & target) as it travels though the corners of both squares in the columns adjacent to the player (player's left) and target (target's right). – msimmons Oct 13 '14 at 14:46
  • hehe .. well that's related to the accuracy! I did the easiest, simpler thing: For every X paint an Y (or viceversa depending on what measure is longer). The values come straight from the equation of the line. What you suggest means that one of those squares left blank was left blank by "very little" in comparison to the one colored. See the "Math.ceil": It rounds to the lower value. So if the equation of the line says y=4.99999999999 I'm coloring square 4 instead of 5. If we use Math.floor (round to the upper) the opposite will happen: an y=4.51 will mean y=5. – rupps Oct 13 '14 at 16:08
  • 1
    ... to solve this, you'd color one additional square depending on the decimal part. This happens because we're using a "coarse" resolution, ie, we only considering x=0,1,2,3,4 and y=0,1,2,3,4: The concept of "square corners" don't exist in our simplification. Take a look at http://jsfiddle.net/57p12h55/6/ where we paint both the Math.ceil() and the Math.floor to better understand it ! – rupps Oct 13 '14 at 16:10
  • @rupps - Thanks! This last one seems more in line with what I had in mind. If either (or both) of those squares are occupied, then they would be blocking the view to the one in the corner, so detecting both is ideal. – msimmons Oct 14 '14 at 00:10
0

Hmm I'm not totally clear on how the 'shooting' works (is it a diagonal or straight shot?) but this one way you could go about it.

Add a 'player' class to the span where the player resides. Get it's 'name' attribute so you know where it is. i.e.

var playerLocation = $('.player').attr('name'); // in this instance r4c3

Get the location of the monster based on the click event i.e.

var monsterLocation = $(event.currentTarget).attr('name'); // in this instance r1c2

So let's say any piece between rows 4 and 1 (occupying 2 and 3) technically block the shot (I know that's probably not how it works but you can tweak the logic for that. From here you can loop through those two rows checking each column to see if a monster is there.

var startingRow = parseInt(playerLocation[1]) + 1; // in this case 2
var endingRow = parseInt(monsterLocation[1]) - 1; // in this case 3

for (var i = startingRow; i < endingRow; i++){
  var tile = "r" + i + "c";
  for (var j = 1; j < 6; j++){
    tile = tile + j; // i.e. r2c1
    if ($('[name=tile]').hasClass('skillRangeSquare') { // using skillRangeSquare because that's what you used in your fiddle
      // if we are here we're blocked
      alert('blocked');
      break;
    }
    tile = tile.substring(0, str.length - 1); // chop off the number we just added to the string
  } 
  alert('hit');
}

So now say you want to base this off of some sort of direct vector from the player to the monster, you'll want to get the x,y position on the page of the player span and the click event, then use logic based on the those coordinates to determine which rows to check (I can give you more detail on this if that's what you're going for). Hope this helps. Note: I didn't actually test out any of this code it's more of a psuedo code example.

rsahai91
  • 437
  • 4
  • 13