Thursday 30 April 2015

Dallas Fuzz Factory guitar pedal with AC128 germanium transistors

I've recently been learning how to play my guitar.
Not just banging out chords, as I've been doing for over twenty years now, but actually play the thing. With riffs and licks and the like. I got the Griff Hamlin Blues Guitar Unleashed course, and his Five More Easy Blues Solos lessons, and set about learning some guitar leads.

I've had the courses for about 8 months now, and still haven't got round to really spending any time with them -  I'm not much further on than I was when I first tenatively plucked out the opening notes of Ugly Kid Joe's "Everything About You" back in the early 90s.

Someone suggested going to a live jam session - not only to learn from others, but to put myself in a position where I have to learn something new or interesting, so I've something to "show off" on the night. So I attended a couple of Blues Jam Meetups and have played live with a band a couple of times now. At one point I even got in front of the mic and sang a little song


One thing I'm not mad about is bands where the guitarists "compete" over the course of the night, getting louder and louder. But there I was, on stage, with 12 bars to fill with some guitar noise. So I broke out my three guitar licks I knew and played them. And it sounded ok. But what I really needed was an extra little bit of oomph, just for the guitar solo - after that night, I decided that what I needed was a stompbox!

About a million years ago - ok, about two-and-a-half - at BuildBrighton we ran a build-your-own guitar stompbox effect workshop.

It was really well attended and everyone - eventually (some returning the following week) - went away with a working pedal. So we have a design which we know works. But one thing that's always been a bit of a bugbear is how it was constructed using perfboard.


Sure, that's great for the workshop, as it demonstrated the "hack-it-together-yourself" approach we wanted to get across, rather than just a "solder-this-existing-kit-we-made" type of workshop. But it always felt a little bit incomplete. But, just for this project, a PCB just felt right. So we set about designing one...


The schematic is a slightly modified version of the original one, with all of the controls brought out onto the front of the pedal


This design includes pots for
  • stability
  • compression
  • gate
  • drive and
  • volume
The PCB layout was designed so that the pots could be fixed straight to it, and that it would lie at 90 degrees to the "face" of the box, to reduce the amount of space that the actual circuit board took up, inside the box.


Amazingly, after soldering everything (ok, most things) up, it all still fit in the enclosure just right


Here's the final pedal, with all the plugs added, pushbutton fitted and all controls in place.



Maybe we could ask Steve to design us a funky new sticker for the top surface.

The only slight problem we have with this now is that is uses some old-school AC128 germanium PNP transistors - and we haven't got any here to actually test the pedal with! Perhaps Jason will turn up with a pocketful of them at tonight's BuildBrighton Open Evening?


Wednesday 29 April 2015

SMT LED fail

While making some double-sided PCBs, we had quite a few left-over press-n-peel copies of our PCB design. It seemed a shame to waste them, but we didn't want to go through the trials of making more double-sided PCBs, so thought we could make single-sided versions of our sci-fi scenery walls.

Making single-sided PCBs is a doddle compared to double-sided (though quite why double-sided proved such a headache, we're still uncertain). It didn't take long to get a few boards etched and soldered up with some SMT LEDs.


For this particular design, we're using just a 74HC164 shift register to sink current through the LED to make it light up. Even without the shift register in place, we can test the board so far, by simply applying a low voltage (up to 3v) to the rails of the PCB.

So we did exactly that - applied 3v to the common power rail that is running to one side of every LED, and grounded the opposite sides of the LEDs, though the traces on the board. As each one lights up, we at least know that the LED has been properly soldered to the board, and that there are no breaks in any of the traces.

Except nothing lit up. Not a thing.

We checked our 2xAA batteries and they were working fine - the problem seemed to be with the PCB. Which, given it's only a few LEDs and some traces, seemed unlikely.

Reluctantly, we tried with the polarity reversed.
And every LED lit up, one at a time. Every LED had been mounted backwards!


Now the odd one might be forgivable - but to solder every single LED back to front it just plain crazy! We were quite diligent in checking the markings on the underside, to make sure that they were being soldered the right way around - but somehow, we'd managed to mis-read the markings on every one of the LEDs.
Then we came across this article online:
http://blog.screamingcircuits.com/2013/01/how-not-to-mark-a-diode.html

And it turns out that we're not the first ones to have had this problem. It turns out that some suppliers use the same markings to indicate different things!



In fact, sometimes the same manufacturer uses the same markings to indicate different polarities in the LEDs! So you can't always just assume that the markings on the underside of the LED will always indicate which way around they need to be mounted on the board.

In short, we're going to have to double-check every LED before placing it, to ensure it's the right way around. Our SMT LEDs have been dispensed into little multi-compartment boxes; we've no idea which are which, who made them, whether their markings indicate the anode or the cathode.... even a simple thing like an LED has suddenly just got a whole lot more complicated!

Double-sided PCB fails

It feels like ages since the Nerd Unit Laser Cutter was fired up, so we put that right this weekend. There are a number of projects on the go (as always) but it was good fun to fire up the laser and etch some boards, instead of messing about with laminators, press-n-peel, and the frustratingly awful Brother laser printer (the old Xerox was a joy to make PCBs with - this Brother laser printer makes every board a hit-and-miss affair).

Anyway, one thing we thought we'd try was some double-sided boards.
It seemed easy enough in principle - firstly, etch our PCB designs onto some MDF and drill out a few holes.


MDF?!
This is just going to be a template for etching; the idea is to place the copper boards on top of the template and when we hit "etch" again, it should carve the same pattern in exactly the same place on the board.


So after etching one side of our double-sided copper board,we drilled the same holes as we had done in our MDF template. Then simply push some pins (we used 0.8mm copper wire) through both the board and the MDF, to get the reverse side to line up


Tape the copper board to the template, spray with matt black paint, etch the reverse pattern, and.... ta-da!

Not exactly successful. The holes are probably a good 3mm away from where they should be!
Undeterred, we went back to the trusty old method of press-n-peel.
There are a few articles online about how to make double-sided boards with press-n-peel, and many use this same approach:



The idea is to print the design twice, one flipped (and mirrored if necessary) with a line exactly half way between the two designs. This is where we're going to crease the press-n-peel. To ensure that we got a perfect line up, we cut our press-n-peel along the very top of the design, and made sure that, after folding, the two top edges were perfectly aligned.


Insert the (double-sided) copper clad board, affix in place and laminate to secure the image


This time the alignment was better - but still not perfect (or, to be honest, not even good enough to be used!)

[photo here]

So in a last-ditch effort, we scrapped all the fancy-shmancy ways of making double-sided boards and went back to the method we know works best - etching just one side at a time.
This involves placing one design on one side of the board (using the "traditional" press-n-peel method) coating the reverse with paint (to protect the copper during the ferric chloride etching) and etching the board as if it were a single-sided PCB.


Then we drill a few alignment holes and clean the back of the board...


...and manually align a second design onto this reverse side.


Alignment is still not perfect - in hindsight, we should have image-transferred and etched the boards before cutting them down to their final size, so that the masking tape holding the press-n-peel in place had a bit more material to stick to!

Although not perfect, at least the alignment of the holes means this board will actually be useable. So the last thing to do is coat the front side (the bit that's already been etched) with paint (to protect it from the ferric chloride during the second etching) and to etching the reverse of the board.


And there we have it. A double-sided PCB that sort-of lines up.
Today's lesson - if you want to make something as quickly as possible, slow down, take your time, and don't try to do anything clever.

Friday 24 April 2015

DIY guitar kits in Saltdean

My usual hardware store shopping list probably looks something like this:

  • Jayes cleaning fluid? Check.
  • Bin bag? Check
  • Pan scourers? Check
  • Multi-part DIY guitar kit? Check.

Ok, maybe that last one doesn't always make the list.
But that might change, after a recent discovery!

After helping a friend with his cooker hood, I called in at a little hardware store, on the main high street in Saltdean. Steve had already recommended calling in, just because of the bizarre combinations of things sold in there. So while I was in the area, I took the opportunity to see what he was on about.


And there they were - in the middle of a hardware store, among the tins of paint and rubber gloves and packets of wood screws, was a selection of DIY guitar kits!


Each kit comes complete with all the hardware for each particular guitar. So with the flying-V guitar, you get a Gibson-style fixed bridge and two humbuckers, with the Telecaster you get a maple-necked fretboard and two classic single-coiled pick-ups. The Warlock style guitar even comes with a Floyd-Rose style floating bridge, and locking nut!

Prices range from £140 to £160 - which when compared to a new instrument, isn't too bad at all. In some ways, these are even better than the cheaper-end guitars on the market, as each has a solid wood (mahogany) body (though the Les Paul copy has a striped maple veneer on top). That's far better quality than my first Squire Strat from over twenty years ago, which - even back then - had a plywood body!

Most of the range, other than the Telecaster, have rosewood fingerboards. I quite fancied trying a maple fingerboard again (my very first guitar had a shiny maple fingerboard, and every other guitar I've owned since then has been rosewood) but I really don't like the Telecaster shape (nor the slightly twangy sound from the rather basic electronics).

So what's the downside? Well, you've got to put it together yourself. You've got to put in the time and effort to get a decent finish. Some of the guitars on display were absolutely stunning - lacquered and sanded back and polished and lacquered and sanded back and polished about five or six times. And it showed. A couple looked like they'd been thrown together, just to complete the display!

So to get a really nice finish, you need to be prepared to put in a bit of work.
But other than that, these kits look like a really nice, relatively easy introduction to making and setting up your own guitar.

They're obviously coming out of China, but with modern CNC routing tools, there's no difference in build quality between these and the Fenders coming out of Korea, Mexico or even the US. Maybe the purists would balk at the idea of using anything but the most exclusive, expensive hardwoods, but for the price, these are pretty decent instruments.

The action on the few guitars I tried there was nice and low, without being "buzzy". The necks are nice and slim (my first Squire had a neck like half-a-drainpipe, it was so fat and round!) and easy to play on. The guitars were pretty much in tune, straight from lifting them off the shelf, despite just hanging in a hardware store for weeks at a time, so the machine heads and other hardware seems to be of decent quality.

 I haven't heard them through an amp, so have no idea what the electrics are like.
But the feel of the constructed demo models was pretty good.
Now I just need to rack up my brownie points, so I don't create World War Three when I come home with a new Flying V or Warlock in pieces in the next few weeks......

[edit: the website hasn't been updated for a while, but the kits are available online at http://diyguitarstore.co.uk ]

Tuesday 14 April 2015

Using a 74HC164 shift register as an LED driver

Earlier in the week, Jason emailed to ask exactly what the problems were with using a shift register to drive eight LEDs. He's used numerous '595 shift registers in his POV globe successfully, and never had a problem with multiple LEDs lighting up and causing the display to dim.

Perhaps the clue was in the original question all along - what's the problem with driving LEDs? Well, the main problem seems to be sourcing current instead of sinking it.

Admittedly, Jason was using some inline resistors on his LEDs which may have limited the current slightly on each LED, but the main problem we'd had with our 595s was that we we driving - i.e. providing positive voltage to - the LEDs through each pin of the shift register.

Different manufacturers of different shift registers give different technical specifications; but one thing that most are clear on - you can almost always sink a lot more current that you can source it (the NXP shift registers we have here also have internal clamp diodes, allowing you to sink a higher voltage than the supply voltage - but that's a whole other issue).

Now we're trying to create a circuit board on a relatively small space, and don't really want the components to be all that obtrusive (since the panel, once soldered up, is supposed to be the wall of a sci-fi interior). If we really have to, we can put inline resistors on each LED, but for testing, we left them off.

Instead of sourcing current, we joined all the anodes (long legs) of the LEDs to our 3.3v power supply. The cathodes (short legs that normally go to ground) are connected to the output pins of a couple of shift registers.

We've gone for 74HC164 shift registers, over the 595s, because these don't require a latch line; this means that the outputs change immediately as the data is shifted in, but it also means one less connector on every PCB section. Using exactly the same firmware as before, we simply cascaded the "last" output (i/o7) to the "data in" pin on the next shift register in the chain and wired up the clock and data lines to our PIC 16F1825.






Rather fortuitously, everything worked first time. Even better than that, everything worked, without current limiting resistors on the LEDs - and they all appeared to be a uniform brightness!


This was very encouraging - we've managed to lose on of the required connecting wires (no need to latch) and we've got uniform brightness, even when multiple LEDs are lit up. The only downside so far is that there's a very noticeable flicker each time the data is sent, as the shift register outputs update with every clock cycle:


Although not too obvious in the video, because of the camera frame rate, every now and again you can see a visible flicker as the LED patterns update. This is more noticeable in real life.


Fixing this flicker shouldn't be too difficult to resolve. At least, the flickering during updating can be eliminated - or at least, replaced with one, single flicker: since the LEDs are all sharing a common power supply, one solution might be to put this power rail through an NPN transistor (something like a 2N2222 perhaps?)

Just before pushing more data to refresh the display, we could turn off the transistor (starving the LEDs of their supply voltage so they go out) then push all the data into the cascaded LEDs (there may easily be twenty or thirty or more in a chain) then bring the transistor back up, illuminating all the required LEDs at the same time.

It will mean one single (possibly longer) flicker when the lights change, but - given that there could be a relatively large number of shift registers all cascading off each other - this is preferable to seeing the data flicker on each data/clock cycle on every wall section. It also means that the transistor becomes like a "latch" - but the latch line does not need to be cascaded along the entire chain of shift registers.

It's food for thought. We're hoping to get a few PCBs etched this week, so we'll be able to try out a couple of different designs, using both the LED driver and these shift registers, and compare the performance of both.


Friday 10 April 2015

Testing TLC5916 LED driver with a PIC 16F1825 microcontroller

Combining the benefits of the MAX7219 (namely, constant current, non-dimming LEDs) with the ability to cascade ICs in a "chain" (like the 74HC595 shift register) has opened up some interesting possibilities for interactive, light-up sci-fi terrain.


Using them is really as simple as treating them as cascading shift registers. The only other thing to take care of is the current limiting resistor (from pin 14 to ground). We're using a 1.5K resistor with a 3.3V power supply and the LEDs are nice and vibrant, without being eye-burningly bright.

Here's some sample code which just displays a recognisable pattern on our cascading chips, to demonstrate that they work as expected:

Define CONFIG1 = 0x0804
Define CONFIG2 = 0x1dff
Define CLOCK_FREQUENCY = 32
AllDigital

declarations:
     Symbol tx = PORTC.7
     Symbol rx = PORTC.6
     Symbol data_out = PORTC.3
     Symbol clock_out = PORTC.5
     Symbol led_out = PORTA.2
     Symbol latch_out = PORTC.4
     
     ConfigPin tx = Output
     ConfigPin rx = Input
     ConfigPin clock_out = Output
     ConfigPin data_out = Output
     ConfigPin latch_out = Output
     ConfigPin led_out = Output
     
     Dim wall_pieces As Byte
     Dim g As Byte
     Dim h As Byte
     Dim i As Byte
     Dim j As Byte
     Dim k As Byte
     Dim data(128) As Byte
     
initialise_chip:
     OSCCON = 11110000b 'oscillator = 32mhz
     WaitMs 10
     APFCON0 = 01000000b 'APFCON

     wall_pieces = 2
     
initialise:

     Low data_out
     Low clock_out
     Low led_out
     Low latch_out
     
     data(1) = 11100111b
     data(2) = 00011000b
     data(3) = 10100101b
     data(4) = 01011010b
     data(5) = 00001111b
     data(6) = 11110000b
     
     g = 1
     WaitMs 500
               
loop:
     
     Gosub send_data
     High led_out
     WaitMs 500
     Low led_out
     WaitMs 500
     
Goto loop
End

send_data:
     
     Low latch_out
     
     'send as many bytes as we have wall pieces
     For i = 1 To wall_pieces
          k = data(g)
          
          'we can only send 7 bits
          For j = 0 To 7
               h = k And 00000001b
               If h = 0 Then
                    'send a zero bit
                    Low data_out
               Else
                    'send a one bit
                    High data_out
               Endif
               
               'the led driver can run at 30Mhz, our PIC is running at 32Mhz
               'in truth, it shouldn't be a problem, but just in case, let's
               'add a tiny delay on the clock line.
               High clock_out
               WaitUs 1
               Low clock_out
               
               k = ShiftRight(k, 1)
          Next j

          'now give it a sec just to let everything settle
          WaitMs 1

          g = g + 1
          If g > 6 Then g = 1
                    
     Next i

     'now latch everything with a falling edge
     High latch_out
     WaitUs 10
     Low latch_out
     
                    
Return



It's important to note that the LED driver chip sinks rather than sources current, so you need to connect your LEDs with a common anode (all the long legs connected to the power rail) and as each output on the driver chip is activated, the appropriate pin is pulled to ground, causing the LED to light up.



After proving that the chips work in the way we expected them to, it was back to our favourite PCB editor, ExpressPCB, to design a double-sided board with up to eight LEDs on it.

In our original design, we spaced fewer LEDs around, so that combinations of different colours could be used. In practice, it's probably quite likely - given the small distances between the LEDs - that the player would rather have one area of the game board one colour (rather than a combination of lots of different colours).

So our PCB layout (above) places eight LEDs in relatively close proximity to each other. The ones in the top corners, for example, might both be red, with the lower row of six being a combination of, say, blue, green and, perhaps, yellow. This would mean the player might switch on only the blue LEDs, to make that particular section of the board glow blue, or only green, or perhaps flash red (as some kind of Star-Trek-alike red alert). It's unlikely to be useful to be able to light up more than two colours at any one time, which is why we've placed them relatively close together, instead of spreading them across the entire surface of each wall section.

With the PCB designed, and the circuit tested and proved to be working, all that remains is to etch a couple of double-sided boards and try the idea out! Luckily the weekend will soon be upon us, to give us chance to pop down to the Nerd Unit and laser-etch a few boards...

Wednesday 8 April 2015

Interactive sci-fi terrain

The long Easter weekend gave us plenty of time not just to mull over a few wacky ideas, but also afforded a few hours to actually put them into practice.

One of the things we looked at was creating some laser cut sci-fi terrain for our larger, 35mm grids.

This meant simply drawing up some vector shapes in Inkscrape and preparing them for laser cutting. It started out pretty simple - some double-length walls, about 68mm long, some inter-connecting pillars (for joining the wall sections either in a straight line, at 90 degrees, or combinations thereof) and spacing them all out onscreen so that, when clipped together, the fit perfectly in our 35mm grid system.

Instead of the relatively chunky 3mm, we designed these to be cut from 2mm MDF. The wall sections are pretty small and fiddly anyway, and we didn't want to make them more difficult to handle, by making them from extra-chunky stock.


Then something went a bit weird. Without even breaking out our favoured ExpressPCB, pads and circuits just appeared on the drawing....

What if, instead of being cut from 2mm MDF, the whole thing was cut from 2mm copper-clad PCB board? That would mean we could put some surface-mount LEDs on them.

And what if we could control individual LEDs? A simple shift register should suffice, allowing multiple walls to be daisy-chained together, all individually controllable from a single source. What if each panel had a few different coloured LEDs placed on them, so that, at the touch of a button, you could - for example - make an entire board area turn red to indicate "red alert"? Or door panels with red and green LEDs to indicate whether the door was locked or open?

Suddenly there was a world of possibility with this "interactive sci-fi wall panel" idea. In fact, since our board game is dependent on some hardware to act as a bridge between a smart device (phone/tablet/PC) and uses serial messages to pass data around, we could re-use the same technology and simply build a stand-alone app, to allow the user to switch lights on and off around their playing surface....

There was nothing for it: we had to crack open the Ferric Chloride!


One thing we hadn't considered (until it came to actually trying out a single wall panel) was that using 74HC595 shift registers meant that every panel needed a five-way connector (power, ground, clock, data, latch lines).


This was a rather chunky connector, and wouldn't work at all well with lots of tiny little, fiddly interlocking pieces. We needed a way of getting that pin-count down.

The Roman Black website has some great ideas for doing just this kind of thing. His site gives a great, detailed explanation about how you can use capacitors and resistors to create an RC circuit, to delay triggering the data/latch pins from a single clock source.


In theory this all sounds great. There's no reason why we couldn't mount a few discrete passive components on each board, and dress them up to look like sci-fi panels on the walls. In practice, things weren't quite so straight-forward.


Here we've connected two shift registers, one cascading into the other (yes, there are three on the breadboard but only two are actually connected together). While the PIC correctly activates the appropriate output pins on the first shift register, the cascade effect fails to send the data on to the second (and, if there were more than two, any subsequent) registers in the chain.

So a single-wire approach is achievable - but only at the cost of losing the cascade ability (and without being able to cascade data from one wall section to another, it'll be really difficult getting any except the first panel to light up!) Maybe we could tie the latch and clock pins together, and reduce our connection count to four pins, instead of five?


By tying the clock and latch pins together (it even suggests you can do this, in the datasheet), we need to provide on extra clock-pulse at the end of sending our data (since the latch is always one clock pulse behind the data). This worked fairly well, but we then discovered the downside of the shift-register approach:

Each shift register is able to source only about 16mA-20mA across all its outputs; roughly the same as the total output of a single PIC i/o pin. That's no problem if we're only lighting one LED at a time. But if we want to light up multiple LEDs, each one gets progressively dimmer, as more are lit at the same time. This could prove to be a real problem, as we've no idea which lights (or combination of lights) the user is likely to want to illuminate at any one time.

What we really need is some kind of constant current, multi-channel, LED driver....
Sometimes you need to invest a bit of time to discover what isn't going to work, in order to work out what is the best way to proceed with some projects.

This weekend we've done just that. We know that not only is a single-wire shift-register unsuitable for, let's be honest, a bit of a crazy whim idea. But investing a bit of time into trying alternatives demonstrated that shift registers aren't exactly the best idea for what we want anyway.

So we've a few TLC5916 LED drivers on order from Farnell.
Etching some PCBs should be straight-forward enough - though quite how we'll cut them into those strange shapes remains to be seen.....

Friday 3 April 2015

Video showing Unity5 collider problem

Here's a short video demonstrating the problem we're having with our Unity5 box colliders.


The game works by selecting a square containing a character (presenting a playing piece on a tabletop miniatures game). If the square contains a character, that playing piece is said to be "in hand". To demonstrate which square the playing piece is in, we place a new game object (a cube for visibility) on the tile that contains the playing piece

A destination square is selected by clicking on another tile. In Unity, I'm working out which tile has been clicked, and placing a cube on it, to ensure that it's not my tile-selection routines that are screwy. From now on, all calculations, rotations, translations and raycasting are done between these two objects (called sourceObject - the one in the starting square, and targetObject - the one in the target/destination square).

The first time a target square is selected, Unity correctly identifies that the ray from the start point to the destination, on the other side of a wall, passes through the box collider on the wall object. The view flips to the "scene" mode, where you can see the two rays being drawn from source to destination.

The second square selected is also on the "wrong" side of at least two walls. Unity again correctly detects that the ray passes through a box collider and will not allow the character to move into the new target square.

The strange stuff happens when we select a point closer to the wall than the character is. When the third target point is selected, you can see that the rays clearly pass through the wall, but the box collider is not detected, and our character happily walks through a solid wall!

Not just a wall with a collider - but the very wall with the very same collider that it detected earlier, when the target square was further away....

Now to make sure it's not a bug introduced when we move our character around, we repeated the test, this time moving the character before attempting any box collider checks:


Here you can see the character is moved to a new square, and target squares are selected behind the walls. The first time we select a target square, the box collider on the wall is detected and our character cannot move to the destination point.

The second destination point is also "behind" two walls, and Unity correctly detects the box colliders on the door and wall, and the character cannot move.

So what gets really frustrating is that the third point - on the "wrong side" of the very wall that it earlier detected the box collider on - does not trigger the box collider, and Unity animates our character walking through a solid wall.

We can't come up with a reasonable explanation as to why this is happening, other than noting that the problem mainly occurs when the box collider hits the "second half" of the ray. In other words, if our character is further away (in terms of straight-line distance) from the wall with the box collider on it, than the target square is, the raycast does not detect the box collider.

If we choose a target square that is sufficiently far away from the wall (box collider) so that the character is closer to the collider than the target point is (on the other side of the collider) then Unity correctly detects the presence of the box collider and reports a break in our line-of-sight.

It's all rather worrying: if we can't rely on the Unity game engine to handle things like line-of-sight and raycasting, we may as well write the entire LOS routines ourselves, from first-principles and GCSE level trigonometry/mathematics - and we've already done that once in Flash. Unity was supposed to free us up from all that, and make things simpler, not more complicated!!


More Unity Raycasting woes

This Raycasting malarky was supposed to make things simple.
And if it behaved the way we understand it to, things like line of sight (for placing pieces, showing and hiding pieces, and for shooting at enemies) would be a doddle. But it's not.

It's really confusing.
And there's not much clue as to why sometimes our line-of-sight works, and sometimes doesn't.

To create a line of sight, we select a source square (the place you're travelling from) and a destination square (where you want to move to). We create two temporary objects (I created cubes just so they would appear on screen, but they can be empty gameobjects) and place them in the centre of the source and destination squares.



We turn the squares to face each other, so that their rotation represents the direction of travel. When we cast a ray from the source point, in the direction of the target, using

var ray:Ray=new Ray(v1.transform.position, (v2.transform.position- v1.transform.position) );
a = Physics.RaycastAll(ray, dist);
return(a);

The full function is here:

function objectsBetweenSquaresOffset(boardID_start:int, squareNo_start:int, boardID_end:int, squareNo_end:int, xOffset:float):RaycastHit[]{

     // this function takes the centre point between squares and
     // then offsets to the left/right (and to the opposite side on the target)
     // returning anything along the path between the two points
     
     var pt1:point2D=getPointFromBoard(boardID_start, squareNo_start);
     var pt2:point2D=getPointFromBoard(boardID_end, squareNo_end);
     var a:RaycastHit[]=null;

     sourceObject.transform.position.x=pt1.x*2;
     sourceObject.transform.position.z=pt1.z*2;     
     sourceObject.transform.position.y=1.4;
          
     targetObject.transform.position.x=pt2.x*2;
     targetObject.transform.position.z=pt2.z*2;
     targetObject.transform.position.y=1.4;
     
     sourceObject.transform.LookAt(targetObject.transform.position);
     targetObject.transform.LookAt(sourceObject.transform.position);

     // parent the objects to the current character (so when we increase the x values
     // it's relative to the way the character is facing, not just global increase)
     var v1:GameObject=new GameObject();
     var v2:GameObject=new GameObject();
     
     v1.transform.position=sourceObject.transform.position;
     v1.transform.rotation=sourceObject.transform.rotation;
     v1.transform.parent=sourceObject.transform;
     
     v2.transform.position=targetObject.transform.position;
     v2.transform.rotation=targetObject.transform.rotation;
     v2.transform.parent=targetObject.transform;
     
     // now offset the objects either left or right, just a bit
     v1.transform.localPosition.x+=xOffset;
     v2.transform.localPosition.x-=xOffset;

     v1.transform.parent=null;
     v2.transform.parent=null;

     // create a ray from the source object to the target object
     var dist:float = ((pt1.x-pt2.x)*(pt1.x-pt2.x)) + ((pt1.z-pt2.z)*(pt1.z-pt2.z));
     dist=Mathf.Sqrt(dist);
     var c:Color=Color.red;
     if(xOffset<0){c=Color.green;}
     trace("distance to destination: "+dist);
     
     // we tried this and it made no difference
     //var direction:Vector3 = ( v2.transform.position - v1.transform.position ).normalized;
     //var ray:Ray=new Ray(v1.transform.position, direction );
     
     var ray:Ray=new Ray(v1.transform.position, (v2.transform.position- v1.transform.position) );     
     Debug.DrawRay(v1.transform.position, (v2.transform.position- v1.transform.position), c, 30);
     a = Physics.RaycastAll(ray, dist);
     Destroy(v1);
     Destroy(v2);     
     return(a);
}


It's called like this:
The idea is that we assume we're always going to perform a valid move. Then we pass in the boardid and square number of the playing piece (current square) and the boardid and square number of the target square into the function above.


var validMove:boolean=true;

// first check that there's a line of sight between the two squares
// (you're not trying to walk through a wall or a door or something)

var hits1:RaycastHit[]=objectsBetweenSquaresOffset(pieceInHand.curr_boardid, pieceInHand.curr_squareno, boardID, squareNo, 0.8f);
var hits2:RaycastHit[]=objectsBetweenSquaresOffset(pieceInHand.curr_boardid, pieceInHand.curr_squareno, boardID, squareNo, -0.8f);

if(hits1){trace("hits1 returned "+hits1.Length+" collisions");}else{trace("no hits1");}
if(hits2){trace("hits2 returned "+hits2.Length+" collisions");}else{trace("no hits2");}

// first check out hits along the left-hand side
if(hits1){
     for (var i:int=0; i<hits1.Length; i++) {
          var hit1 : RaycastHit = hits1[i];
          if(hit1.collider.gameObject.transform.root.transform==activeCharacter.transform){
               // ignore this, you've just collided with yourself!
               trace("ignore collision with self");
          }else{
               var s1:String=hit1.collider.gameObject.tag;
               // if you hit anything along the way, the way is blocked
               trace("i) path blocked by "+s1+" "+hit1.collider.gameObject.transform.root.name);
               validMove=false;
          }
     }
}

// now hits along the right-hand side
if(hits2){
     for (var j:int=0; j<hits2.Length; j++) {
          var hit2 : RaycastHit = hits2[j];     
          if(hit2.collider.gameObject.transform.root.transform==activeCharacter.transform){
               // ignore this, you've just collided with yourself!
          }else{
               var s2:String=hit2.collider.gameObject.tag;
               // if you hit anything along the way, the way is blocked
               trace("ii) path blocked by "+s2+" "+hit2.collider.gameObject.transform.root.name);
               validMove=false;
          }
     }
}


The collision function converts the current boardid and square number into a pair of points (and does the same for the target square). This function is included below for completeness, but it's accuracy is not in question: the points returned are used to draw the ray on the screen, so we can see that they are correct.

We then place our sourceObject cube and our targetObject cube in the appropriate places on the map. Again, these can be seen as in the correct places, in the screenshot, so there is little question of this being incorrect. We turn the two cubes to look at each other.

We then create a blank object and place this as a child of the sourceObject (and create a blank child for the targetObject too). Then, we shift these blank objects a little to one side (depending of the value of the xOffset parameter passed into the function) by changing their local x co-ordinate (if we changed their global x co-ordinate, the line would not necessarily begin to the side of the cube: local co-ordinates take into consideration the rotation of the cubes when shifting the starting points).

Using a simple Pythagoras equation we work out the distance between the two cubes, and then create a ray between them. We then use Physics.RaycastAll to return a list of all objects collided with along the length of the ray.

The strange thing is, if the point of collision is less than half-way along the ray, the ray successfully detects an obstacle. But if, for example, we place our character two squares away from a wall, and select the target square just one square away from the wall, on the opposite side, something peculiar happens:


Where the obstacle intersects the ray at any point more than half-way along, the box collider is not detected. In the example above, the ray is drawn passing through the door (which has a number of box colliders on it, but we get the same result with a wall section with just one collider) but this time, RaycastAll does not return the obstacle.

The problem is surely not with the box collider on the obstacle, since it is sometimes correctly identified. It only seems be by how much the ray passes through the obstacle that determines whether or not the box collider is detected.

The problem is, we're not sure whether we're not understanding how box colliders work, whether there's a bug in the code that we're just not seeing, whether or not the box collider is set up correctly, or whether there's a bug with Unity and using box collidors on objects that are instantiated in code (online sources suggest that Unity has a bug which can be squashed by disabling then re-enabling an object after instantiating, but even with this in place, we're getting the same results).

A read head-scratcher this one........

Thursday 2 April 2015

Unity line of sight is not the same as "clear to proceed"

Another minor stumbling block this evening, following on from our Unity box collider problems. This time it's not the syntax or Unity programming language that's the problem, but our approach to solving a particular problem.

The issue is this:

Currently we're drawing a single line-of-sight from centre-to-centre of each square. If there are any obstacles between the two selected points, we say that there is no line of sight. That's fine - most of the time....


Here, our hero is blocked from walking diagonally, because it will cause him to walk through the edge of the wall. The routines are correctly reporting that there is an obscured line of sight to the target square.

But what if there was an object (or an enemy character) in the square? If we place the main camera on the character's head, in 3D space, we can see the board "through their eyes". And we can clearly see (at least partially) the squares on the diagonals.


We're pretty sure that if one of those green squares contained an enemy character, we'd at least expect to see part of it. So our single line-of-sight routine is going to fail us - at present, it'll simply report a wall in the way of the target square, and as a result we'll end up not putting the partially visible enemy character in the target square.

What we really need to do is measure the line of sight from two points on "either side" of the character, to two points "either side" of the centre of the target square. If either one of these lines is obscured, we don't want to allow our character to walk to the target (since at least part of the path is obscured). However, if either of the two lines is clear, then this means that the character can at least see part of the target square - and so, has an uninterrupted line-of-sight to the target.


In the diagram above, we created two rays, offset slightly from the centre of the originating square, to points either side of the centre of the target square. The green ray passes through the wall (and our routine correctly identifies that the wall is in the way.

However, because the red ray reaches its destination unhindered, we can report a line-of-sight between our character and the target square. If any enemy character were in this square, it should be displayed and placed on the board.


Unity box collider not quite working properly on the diagonal

That's quite a mouthful for a title - but something that has chewed up many hours trying to resolve. It'll probably take forever and a day to explain exactly how we ended up at this, suffice to say that after getting our web-based map editor successfully creating maps for our Unity 3D app, we're now busy coding behaviours and game-logic; and it's not exactly been plain sailing!

The long and short of it is, we're using Unity's inbuilt Raycasting to calculate line-of-sight and other obstacle detection routines. The idea is that you select a playing piece, select a destination, and the code will work out if you have an un-obscured path to the destination (if you have, the character walks into the target square, if not, a wakka-wakka-oops sound plays, to let you know that your instruction was rejected as invalid).

But Unity's built in Raycaster is not without it's problems.
Sure, it works fine if you draw a ray from a point and it collides with a large face in your box collider:


Here, we've tried to make our character walk through a door. We draw a ray from the source to the destination squares and then walk through the hit-objects collection, to see if any objects have been tagged as either "wall" or "door" (if we have, we can't walk in the selected direction).

This works just fine. But when we approach our walls from an angle, things start to go a bit screwy. As we approached this opening, we had a free square immediately in front. The squares diagonally above and below this one were free, but partially obscured by a wall:


The Unity RaycastAll correctly returned the wall as an obstacle that couldn't be walked through. But when we selected a target square on the other diagonal, something peculiar happened:

(the direction of the ray has been added to this screenshot)

This time, we can clearly see the ray passing through our box collidor.... but the RaycastAll function returned zero collision objects.

Where things got really weird was when we reversed this ray/vector, and tried to walk back to the square we'd just come from:


This time, the Unity RaycastAll function said that there was a wall in the way! So the wall it didn't recognise when attempting to travel in one direction has suddenly become noticeable, when approached from the other side!

We speculated that this was perhaps because the first time, our ray entered the "side" of the box collider and passed through the "front" of it - whereas when approached from the other side, we're hitting the "front" of the box collider before exiting out of the side.

This theory seemed to hold up because if we increased the width of the box colliders (so that they extended slightly beyond the actual edges of the object) the raycast detect function seemed to work again


Except (although not immediately obvious in the screenshot above) the ray is still entering the "side" of the box collider. It's almost as if the box collider is not a box at all, but a "cross-shaped" intersection of two planes - and by approaching diagonally from the side, if the angle is just right, the ray does not intersect the plane passing down the centre of the box - make it a little bit wider, and suddenly the ray passes through it.

Making over-sized box colliders feels a bit "hacky".
There's just something not right about it.
But it sort-of works for now, so we're going to leave it at that.

We'd much rather understand why it is happening, and take care of it "properly" rather than fudge a way around it. It's like the suggestion that each object should be disabled and re-enabled after re-sizing or re-positioning, because this too can affect the way box colliders work.

We've already done that (disabling then re-enabling the objects, as well as their respective box colliders after positioning them onscreen) but it make no difference.

The hack sort-of works. But we can't help but feel that this issue is going to come back and bite us on the arse sometime in the near future!