Rick's b.log - 2024/12/25 |
|
It is the 27th of December 2024 You are 3.149.255.239, pleased to meet you! |
|
mailto:
blog -at- heyrick -dot- eu
Anyway, I'd like to wish everybody a happy holiday.
I am mostly writing this in response to an article I saw about a delivery driver in America who was fed up and stressed and a few days ago dumped a load of Amazon parcels in the woods. They were quickly discovered and, I think, returned to Amazon (sucks to be you if those were your presents...).
One of the reasons they are upset is that Amazon apparently pays $15/hour and some organisation says that a living wage in the US is $22.20/hour. I suppose one would need more money in the US because the number of things we take for granted like social care, access to medical facilities that won't backrupt us, and suchlike are absolutely not assured in the US. However, to put it into context, my wage equates to $12.30 (brut, that's not what I get in my pocket).
For what it is worth, I have no sympathy and hope this driver gets told to walk. Why? Because if they were stressed out, the correct action would have been to take the parcels back to the depot. They are things that people paid for and are depending upon that person to deliver. Yes, delivery drivers get a crap deal, we all do these days, plus Amazon is notorious for this - it's something that often turns up in newspapers. To just dump everything like that? No, that's crossing a moral line.
Immediately a number of right-wing Americans, like J.D. Vance, took shot at the Associated Press with questions like "Who was driving the car?".
Of course, things get decidedly murkier when it turns out that the man, a Saudi doctor, was a right-wing supporter who apparently did this atrocity because he was angry about the Islamification of the country. Like, huh? Talk about throwing a spanner in the works of the usual racist right-wing bollocks.
So if it is bad for the non-right-wing press to be cautious in what they report, let's take a quick look at what the right-wing press were up to. Fair's fair, right? While we currently know that five people have died, on the night the news unfolded it was known that there were two deaths. GB News, however, went with this story.
Why? Around two hundred people have been injured, some of them seriously, and there had been two (now five) deaths. Why did they run an article claiming eleven? Could it possibly be that it was for additional 'shock value' (as if the event wasn't shocking enough) to permit opening a dialogue that basically boils down to "Islam is evil"?
I'd like to link to the article, but all I have is the screenshot that I was prescient enough to take, because it appears as if the article no longer exists. That's the mark of quality journalism right there - make up bollocks and erase it once reality proves it wrong. But, then, the right wingers are like that. Look at just about everything said about Brexit as an example. Or what the next four years of POTUS will bestow upon humanity.
<shrug>
He took one of the cake mixes out to put it under the 2kg weight limit and sent it by Royal Mail. It has already made it to France, and has cleared customs. However, since there is no customs agreement with the UK and the EU, I'm being scammed for a "handling" charge. Luckily this time I was able to pay online (unlike with the Tilley Lamp parts), so it was only €7 rather than the usual €11.
It may come in the next few days. It'll be interesting to see what happens when she hands me a bill for the full amount and I'll reply with "Nope, I've already paid that". It seems that left hand and right hand barely talk to each other. It's almost as if nobody ever imports stuff by post and so La Poste doesn't really know how to handle any of this stuff, isn't it?
But, really, being scammed for a "handling fee" for them doing what they do anyway. Yet another reason to say F██k Brexit.
If we want to be cheap'n'cheerful then that is it. The height of the wall is inversely propertional to the distance - that means closer walls are taller than ones farther away, so it's pretty simple, also, to calculate how big the wall should be. Simply divide the height of the screen by the wall distance.
Here is some really naff code to bung that onto the screen in MODE 28. We simply step each ray in turn and draw ten pixels on the screen as a result of it. This is only for demonstration purposes.
As you can see, it's a remarkably small amount of code. It creates the following display.
The way to correct this goes back to trigonometry. What we are ending up with after the ray stepping algorithm is the hypotenuse which is the ray length. If we multiply this with the cosine of the angle difference, we end up with the adjacent, which is the perceptual distance as the player would perceive it. To better understand this, you'll need to dig into that school stuff about right-angle triangles, I'm not going to explain it here. What I will say is that we calculate the difference between the direction the player is actually facing and the ray angle because as you can imagine the closer we are to the sides of the screen, the more correction will be necessary.
In place of the line
This simple, but FP heavy, calculation now provides a good correction so all of the walls look as they should.
Clearly it is simpler if what is shown on screen is the same as what happens internally, but the reason we use computers is because one can hide away such calculations. The user doesn't need to know what's going on inside.
Here is an updated program that displays the screen in a never-ending loop (press
You will notice, as an optimisation, we draw every two screen columns. On my Pi 3B+, this changes the framerate reported from ~19fps to ~38fps while barely changing how it looks on-screen, so it's a worthwhile optimisation.
Now to add rotation. Unlike the series that I wrote a couple of years ago that used planes, this raycaster works with angles and translates those on-the-fly. So all we need to do is increment or decrement the angle that the player is facing.
Replace the part that says "
If you press
I'll remind you, the angles here run anticlockwise which is why one adds to turn to the left.
Put this after the rotation code.
After the map setup at the top, you could add this to have something to walk around.
Have fun playing with this.
Merry Christmas
It is, perhaps, a White Christmas if one horribly abuses the definition of "white". In this case, there is much fog, and everything is drenched.
A White Christmas?Freezer
My freezer is almost full. The section at the top with the door has various ready meals in it. And at the bottom? My favourite drawer. I have over the past few weekends baked various cakes and such. Then, if I feel like something cakey, I just need to take out one and let it defrost.
For when you're feeling peckish for something sweet.Wages
As is increasingly happening, when the government raises the minimum wage, our wage doesn't go up in step. Instead we get straight minimum, as that's the legal minimum. In France there are various categories of worker. The lowest is called OE1, somebody that needs their hands held. Next up is OE2, the production line workers are this - they have line managers to tell them what to do. My category is OE3 because as a washer-upper we manage ourselves and handle our own organisation. We don't have a line manager. And yet, making €11,88 an hour (brut), we're being paid OE1 wages and expected, I presume, to do the rest for free.
The only reason I'm not doing more than whinging on my blog is because I have been there long enough that I qualify for a thirteenth month which adds to the overall take-home (albeit in a lump sum once a year).
Being America, it's that never-ending battle between unions and employers, possible because the delivery drivers are a third party and thus avoided Amazon's infamous anti-union action; but then this sort of thing seems to be all too common in the United States.
Right-wing madness
Immediately following the recent tragic attack at the Christmas market in Germany, the Associated Press went with this headline:
A car has driven into a group of people at a Christmas market in Germany.
Clearly they fail to understand that the AP's wording is deliberately vague because while it sure looked and felt like an act of terrorism, at that point it could have been a horrible tragedy due to the driver suffering, perhaps, a heart attack or somesuch. Sure, it is a remote possibility, but a decent press will report on the facts as they become available. This does not mean that they're trying to downplay an Islamist act of terror by "implying" that the car drove itself into the crowd...something that wouldn't happen on this side of the ocean anyway as we're not dumb enough to use hapless civilians as crash-test dummies for self-driving cars.
Oh, and in case you missed it, this guy was "known to authorities" and they had received warnings about him. You see, the powers that be don't need extra powers to snoop in everybody's lives, they just need to pay attention to the information that they already have.
Because accuracy matters...Dora Advent Calendar
I have just watched an advert for a "Dora Advent Calendar" with new episodes of Dora on the channel Nick Jr. Why am I commenting on this, especially given that I can't even receive that channel? Because it popped up on C5 during an advert break in The Railway Children Return...on Christmas Day, the day after advent calendars are over.
The parcel scam
On the 9th of December, a friend in the UK got me some Betty Crocker cake mix. Royal Mail wanted some obscene amount to send it because it passed the 2kg limit, so the woman at the Post Office offered a cheaper option - a carrier called Evri. He declared it correctly and sent it after he was assured that there wouldn't be a problem.
He phoned me with the tracking number, and the status said "Error". Nothing else. After a few days of this, I made a report using a dumb bot called Ezra. Evri never replied to me, but the status was updated to say that the parcel was being held in Basildon following an error at LHR, return to sender.
Given how much was paid for that parcel, it is ridiculous that it took until Friday 20th to make it back. Actually, it took until the 21st because Evri omitted a line from the return address and ended up sending the parcel to a completely different property, and luckily the person there brought it to the right place.
I have never, not once, heard anything good about Evri. Count this as another data point.
The maths of raycasting - part two
In the previous article I looked at the grimy maths of tracing a ray through a grid to determine when it hit something.
This time, we're going to start to turn it into something vaguely useful - walls plotted on the screen. But before we can do that, we need to know how far away these walls are.
Calculating the distance
As it happens, we already have the distance as a result of tracing the ray. It's xside or yside. However, we do need to subtract the appropriate delta as that will have been added by the DDA, so undoing that gives us our proper distance.
IF (side% = 0) THEN
walldist = xside - xdelta
ELSE
walldist = yside - ydelta
ENDIF
ON ERROR PRINT REPORT$+" at "+STR$(ERL) : END
playx = 4.5
playy = 1.5
MODE 28
DIM map%(8,8)
FOR x% = 3 TO 6 : map%(x%, 7) = 1 : NEXT
map%(2, 6) = 1 : map%(7, 6) = 1
FOR y% = 1 TO 5 : map%(1, y%) = 1 : map%(8, y%) = 1 : NEXT
col% = 0
FOR angdeg = 120 TO 60 STEP -1
angle = RAD(angdeg)
xpos = playx : ypos = playy
xmap = INT(xpos) : ymap = INT(ypos)
xdir = COS(angle) : ydir = SIN(angle)
IF ( xdir = 0 ) THEN xdelta = 123456 ELSE xdelta = ABS(1 / xdir)
IF ( ydir = 0 ) THEN ydelta = 123456 ELSE ydelta = ABS(1 / ydir)
IF ( xdir < 0 ) THEN
xstep = -1 : xside = (xpos - xmap) * xdelta
ELSE
xstep = 1 : xside = ((xmap + 1) - xpos) * xdelta
ENDIF
IF ( ydir < 0 ) THEN
ystep = -1 : yside = (ypos - ymap) * ydelta
ELSE
ystep = 1 : yside = ((ymap + 1) - ypos) * ydelta
ENDIF
wallhit% = FALSE
REPEAT
IF ( xside < yside ) THEN
xside += xdelta : xmap += xstep : side% = 0
ELSE
yside += ydelta : ymap += ystep : side% = 1
ENDIF
IF ( (xmap > 0 ) AND ( xmap < 9 ) ) THEN
IF ( (ymap > 0 ) AND ( ymap < 9 ) ) THEN
IF ( map%(xmap, ymap) = 1 ) THEN wallhit% = TRUE
ENDIF
ENDIF
UNTIL ( wallhit% = TRUE )
IF (side% = 0) THEN
walldist = xside - xdelta
ELSE
walldist = yside - ydelta
ENDIF
wallhei = 480 / walldist
IF side% = 1 THEN GCOL 255, 255, 255 ELSE GCOL 127, 127, 127
RECTANGLE FILL col% << 1, 240 - (wallhei / 2) << 1, 10 << 1, wallhei << 1
col% += 10
NEXT
Correcting fish-eye distortion
As you no doubt noticed, the walls were not drawn straight. The big wall directly in front bulges slightly. The reason for this is that rays cast to either side of the direction the player is facing, that is to say anything not directly in front, travel a slightly longer distance even if they are visually the same distance.
wallhei = 480 / walldist
, write this:
diff% = ABS(90 - angdeg)
corrdist = walldist * COS(RAD(diff%))
wallhei = 480 / corrdist
What's with the weird angles?
Facing 'up' in the grid that we have created is 90°. The degrees move anticlockwise, so counting backwards. There may be ways to resolve this such as running the grid as a mirror image or something, but to be honest it isn't that hard to turn the angle that we use internally into a suitable angle for display that has 'up' as zero degrees and the angles turning clockwise as would be expected.
virtang% = 360 - (angdeg - 90)
IF virtang < 0 THEN virtang += 360
IF virtang > 359 THEN virtang -= 360
Rotation
For any form of movement, we're going to have to do quite a number of changes to the program in order to support proper redrawing. We can't simply dump data to the screen because it may take longer to draw than the screen update and it will flicker horribly. In order to resolve this, let's introduce the concept of buffering - that is to say we draw frames not to the screen itself, but to some memory and then switch what we're actually displaying once the frame has been drawn.
Esc
to quit).
ON ERROR PROCerror
@% = "+G10.3"
playx = 4.5
playy = 2.5
playa% = 90 : REM Actual angle used here
fov% = 60 : REM Field of view
MODE 28
screenwidth% = VDU(11)
screenheight% = VDU(12)
SYS "XOS_ReadModeVariable", -1, 7 TO ,, scrsize%
scrwant% = scrsize% * 3
SYS "XOS_ReadDynamicArea", 2 TO , scrcurr%
screxpa% = scrwant% - scrcurr% : REM How much to enlarge by
IF ( screxpa% > 0 ) THEN
SYS "XOS_ChangeDynamicArea", 2, screxpa% TO ; f%
IF (f% AND 1) THEN ERROR 123, "Not enough screen memory."
ENDIF
DIM map%(8,8)
FOR x% = 3 TO 6 : map%(x%, 7) = 1 : NEXT
map%(2, 6) = 1 : map%(7, 6) = 1
FOR y% = 1 TO 5 : map%(1, y%) = 1 : map%(8, y%) = 1 : NEXT
FOR x% = 1 TO 8 : map%(x%, 1) = 1 : NEXT
MOUSE OFF
SYS "OS_RemoveCursors"
SYS "OS_Byte", 114, 0 : REM Shadow modes
bank% = 1
PROCswitchbank
timeout% = TIME + 100
fcnt% = 0
fps% = 0
REPEAT
PROCswitchbank
CLS
GCOL 0, 127, 127
RECTANGLE FILL 0, (screenheight% / 2) << 1, screenwidth% << 1, (screenheight% / 2) << 1
GCOL 0, 127, 0
RECTANGLE FILL 0, 0, screenwidth% << 1, (screenheight% / 2) << 1
FOR col% = 0 TO screenwidth% STEP 2
colang = fov% / (screenwidth% + 1) : REM Degrees per screen column
angdeg = playa% + ( -(col% - ((screenwidth% + 1) / 2)) ) * colang
angle = RAD(angdeg)
xpos = playx : ypos = playy
xmap = INT(xpos) : ymap = INT(ypos)
xdir = COS(angle) : ydir = SIN(angle)
IF ( xdir = 0 ) THEN xdelta = 123456 ELSE xdelta = ABS(1 / xdir)
IF ( ydir = 0 ) THEN ydelta = 123456 ELSE ydelta = ABS(1 / ydir)
IF ( xdir < 0 ) THEN
xstep = -1 : xside = (xpos - xmap) * xdelta
ELSE
xstep = 1 : xside = ((xmap + 1) - xpos) * xdelta
ENDIF
IF ( ydir < 0 ) THEN
ystep = -1 : yside = (ypos - ymap) * ydelta
ELSE
ystep = 1 : yside = ((ymap + 1) - ypos) * ydelta
ENDIF
wallhit% = FALSE
REPEAT
IF ( xside < yside ) THEN
xside += xdelta : xmap += xstep : side% = 0
ELSE
yside += ydelta : ymap += ystep : side% = 1
ENDIF
IF ( (xmap > 0 ) AND ( xmap < 9 ) ) THEN
IF ( (ymap > 0 ) AND ( ymap < 9 ) ) THEN
IF ( map%(xmap, ymap) = 1 ) THEN wallhit% = TRUE
ENDIF
ENDIF
UNTIL ( wallhit% = TRUE )
IF (side% = 0) THEN
walldist = xside - xdelta
ELSE
walldist = yside - ydelta
ENDIF
virtang = 360 - (angdeg - 90)
IF virtang < 0 THEN virtang+=360
IF virtang > 359 THEN virtang-=360
diff% = ABS(playa% - angdeg)
corrdist = walldist * COS(RAD(diff%))
wallhei = (screenheight% + 1) / corrdist
IF side% = 1 THEN GCOL 255, 255, 0 ELSE GCOL 127, 127, 0
RECTANGLE FILL col% << 1, 240 - (wallhei / 2) << 1, 2 << 1, wallhei << 1
NEXT
REM Movement here!
PRINTTAB(0,0);"X="+STR$(playx)+", Y="+STR$(playy)+", A="+STR$(playa%)+"° ("+STR$(fps%)+" fps)"
fcnt% += 1
IF ( TIME >= timeout% ) THEN
timeout% = TIME + 100
fps% = fcnt%
fcnt% = 0
ENDIF
UNTIL FALSE
END
:
DEFPROCerror
REM Sanitise the display, report the error, go byebye.
PROCdrawbank(0)
PROCshowbank(0)
SYS "OS_Byte", 114, 1
PRINTTAB(0,0);REPORT$+" at "+STR$(ERL)
END
ENDPROC
DEFPROCdrawbank(w%)
REM What screen bank are we drawing to?
SYS "XOS_Byte", 112, w%
ENDPROC
DEFPROCshowbank(w%)
REM What screen bank is the user looking at?
SYS "XOS_Byte", 113, w%
ENDPROC
DEFPROCswitchbank
REM Furtle with the screen banks
WAIT
PROCshowbank(bank%)
bank% = (bank% MOD 3) + 1
PROCdrawbank(bank%)
ENDPROC
DEFFNkey(k%)
REM Returns TRUE if the nominated key is pressed, else FALSE
SYS "OS_Byte", 121, (k% EOR amp;&80) TO , r%
IF r% = &FF THEN =TRUE
=FALSE
You'll also notice that it looks better with some colours. ☺
REM Movement here!
" with this:
REM Rotation (cursor left/right)
IF ( FNkey(25) ) OR ( FNkey(121) ) THEN
speed% = 1
IF FNkey(0) THEN speed% = 2
IF FNkey(25) THEN playa% += speed% ELSE playa% -= speed%
IF ( playa% < 0 ) THEN playa% += 360
IF ( playa% > 359 ) THEN playa% -= 360
ENDIF
Left
, you turn to the left. If you press Right
, you turn to the right. If Shift
is held down, you'll turn twice as fast.
Forwards and backwards
This is harder, because we need to perform two actions here. The first is to perform the movement. For this we need to 'follow a ray' in the forward direction for a tiny step. This will give us a new X and Y position. Guess what, it's more of the sine and cosine functions.
Once this has been done, the second thing to do is to look at the new map coordinate to see what is there. If it's not a zero, not an empty square, then the movement will be reverted to avoid a collision with a wall.
REM Movement (cursor up/down)
IF ( FNkey(57) ) OR ( FNkey(41) ) THEN
oldplayx = playx
oldplayy = playy
IF ( FNkey(57) ) THEN
playx += COS(angle) * 0.1
playy += SIN(angle) * 0.1
ELSE
playx -= COS(angle) * 0.1
playy -= SIN(angle) * 0.1
ENDIF
IF map%(playx, playy) <> 0 THEN
playx = oldplayx
playy = oldplayy
ENDIF
ENDIF
map%(4, 4) = 1
For RISC OS machines.
Rob, 26th December 2024, 00:36 I was listening to Heart Xmas last night, well about 2am this morning, whilst wrapping presents, and almost every other advert was (to summarise) saying to get your last minute gifts at BP/M&S forecourt shops because they were open late. I checked. The nearest couple had all closed at 11pm. Do you think companies just book ads without checking how long they are going to run for?jgh in Japan, 27th December 2024, 02:07 Sh1t! I'm barely on more than you as an IT Enggggg ennnnn (cough!) technician. (checks spreadsheet) £12.54ph
© 2024 Rick Murray |
This web page is licenced for your personal, private, non-commercial use only. No automated processing by advertising systems is permitted. RIPA notice: No consent is given for interception of page transmission. |