惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Full Disclosure
Recorded Future
Recorded Future
T
Tenable Blog
S
Securelist
C
CERT Recently Published Vulnerability Notes
T
Threatpost
S
Schneier on Security
A
Arctic Wolf
The Hacker News
The Hacker News
C
CXSECURITY Database RSS Feed - CXSecurity.com
Know Your Adversary
Know Your Adversary
P
Privacy International News Feed
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
The Register - Security
The Register - Security
Cisco Talos Blog
Cisco Talos Blog
AWS News Blog
AWS News Blog
K
Kaspersky official blog
T
True Tiger Recordings
T
Threat Research - Cisco Blogs
V
Vulnerabilities – Threatpost
P
Palo Alto Networks Blog
T
The Exploit Database - CXSecurity.com
小众软件
小众软件
B
Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Azure Blog
Microsoft Azure Blog
Cyberwarzone
Cyberwarzone
C
Cybersecurity and Infrastructure Security Agency CISA
T
Tor Project blog
Spread Privacy
Spread Privacy
Malwarebytes
Malwarebytes
P
Proofpoint News Feed
F
Fox-IT International blog
F
Fortinet All Blogs
P
Privacy & Cybersecurity Law Blog
G
GRAHAM CLULEY
量子位
Latest news
Latest news
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 叶小钗
Project Zero
Project Zero
T
Tailwind CSS Blog
N
Netflix TechBlog - Medium
Martin Fowler
Martin Fowler
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
I
Intezer
博客园_首页
腾讯CDC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
D
Darknet – Hacking Tools, Hacker News & Cyber Security

Hacker News: Front Page

Big Tech's Anti-Labor Playbook Has Come for Wikipedia More ETFs Than Stocks Chemistry behind the Garden Grove chemical tank Stop advertising in your commits! | AksDev Xiaomi MiMo Api Open Platform - Token Plan Global Launch Stack Overflow’s forum is dead thanks to AI, but the company’s still kicking... thanks to AI Stack Overflow's forum is dead thanks to AI Founding Software Engineer at Sage Care | Y Combinator The Real Cost of Owning a Home — Eric Turner Is “colorectal cancer” rising in “young people”? What Color is Your Function? – journal.stuffwithstuff.com Uber, Lyft drivers in Massachusetts form first US ride-share union The ballad of TIGIT 'Incredible' milestone reached as Sweden becomes a smoke-free country Minicor | Scalable Desktop Automations Don't Subscribe So Casually Stockholm poised to become leading European geospatial intel player Dropbox CEO Drew Houston to step down after 19 years at helm of cloud storage pioneer AWS Fired the One Employee Who Gave a Damn Spain blocks prediction markets Polymarket, Kalshi over lack of gambling licence Outsourcing plus LocalAI will soon become more economical vs. Frontier labs EAGLE 3.1: Advancing Speculative Decoding Through Collaboration Between the EAGLE Team, vLLM, and TorchSpec Netherlands blocks US takeover of vital digital supplier GitHub Status Ferrari shares fall after launch of first EV as Jony Ive design proves divisive Incident with Actions and Pages Modern Blu-ray drives can now rip GameCube, Wii, and Xbox 360 games to PC — third-party OmniDrive firmware unlocks game rips from physical media on select players China vs Taiwan: The Geography of an Unfinished War – The Jerusalem Strategic Tribune Daily links from Cory Doctorow I bypassed AWS API Gateway auth with a trailing slash. Got $12K bounty. Uber president says AI spending is getting ‘harder to justify’ Exposing Critical Vulnerabilities in CBSE’s On-Screen Marking Portal: From Authentication Bypass to Full Account Takeover — ni5arga A reality check on the AI jobs hysteria DynIP — Dynamic DNS that actually works Ask HN: Is anyone working at least 4 hours daily on an Apple Vision Pro? GitHub - andreoliwa/logseq-doctor: Heal your Markdown files: convert to outline, list tasks and more tools to come Ask HN: Pregunta para los devs hispanohablantes Language Models Need Sleep Motorola phones have started hijacking the Amazon app to insert affiliate codes [Video] Earthion: A New Mega Drive-Style Shoot-Em-Up Why The Smart Home Bubble Popped JSX.lol Encrypt Files in Your Browser — Secvant Vault | AES-256 Designing for and Against the Manufactured Normalcy Field TP–7 Notes on Pope Leo XIV’s encyclical on AI About the security content of macOS Tahoe 26.5 - Apple Support Nobody Cracks Open a Programming Book Anymore · unix.foo Chatbot Has a Long Memory. That Isn't Always a Good Thing I Made 6 Frontier AIs Take the MBTI 600 Times. They All Came Back INTJ. Market Outlook: Canada losing top talent as workers head to the U.S. How Shamir's Secret Sharing Works Overview — Agentic Patterns — Veso Research Taking a walk may lead to more creativity than sitting, study finds (2014) I'm done. I'm f***ing done [video] Show HN: OpenBrief – Local-first video downloader/summarizer Microsoft Copilot Cowork Exfiltrates Files It’s finally here: meet the Ferrari Luce, Maranello’s first ever fully electric car GitHub - ghetea-patrick/riscrithm: Riscrithm is a lightweight, low-boilerplate macro-assembly dialect that compiles straight down to pure, human-readable RISC-V assembly. It bridges the gap between the expressive syntax of high-level languages and the raw, deterministic hardware execution of bare-metal computing. Jony Ive's Ferrari A few interesting modern pixel fonts – Unsung Yoti age checks share facial photos and device fingerprints with third parties Ninth Circuit Panel Goes Out of Its Way to Question Section 230–Doe v. Meta Tidy PSU – PD-64 C64 PSU Brings USB PD to Commodore 64 Norway's 2 petabytes of Huawei flash storage and LLM training Anthropic co-founder Chris Olah's remarks on Pope Leo XIV's encyclical "Magnifica humanitas" GitHub - yugr/rust-slides The bootstrapper's EU stack for under €10 per month Weave (YC W25) is hiring ML, AI, product, & design engineers Exit IP VPN servers mitigation rollout The Revenge of The Measurers The User Is Visibly Frustrated Senior AI/ML Lead at RentFlow | Y Combinator Ubers COO says its getting harder to justify the money spent on AI tokenmaxxing Founder of 7/11 Japan, Toshifumi Suzuki, has died at age 93 Using AI to write better code more slowly Chert | iMessage Infrastructure for Reaching People at Scale California moves to exempt Linux from its upcoming age-verification law after backlash over forcing operating systems to collect users’ ages — amendment proposed by the same lawmaker who wrote the original law Hive (YC S14) is hiring sr back-end developers (CA/US remote OK) The Cost of Safetyism On C extensions, portability, and alternative compilers Netherlands Seizes 800 Servers, Arrests 2 for Aiding Cyberattacks 2026 HIPAA Security Rule Update: New Requirements Every Healthcare Organization Must Prepare For Pope Leo XIV says AI must serve humanity, not the powerful few Microsoft pulls plug on plans for 244-acre data center in Caledonia Leave Me Behind I manage teams without a single call GitHub - exmergo/research-chatgpt-guesses-between-1-and-100: When asked to pick a random number between 1 and 100, ChatGPT does not follow a random uniform distribution Pope Leo Issues AI Encyclical Warning Against 'Opaque Algorithms' Encyclical Letter of His Holiness Leo XIV Magnifica Humanitas (15 May 2026) Our Warming Planet Is a Petri Dish for New and Deadly Microbes IBM Spins Off the First Pure-Play Quantum Chip Foundry Rising seas will swallow New Orleans. People need to start relocating now, scientists say Geomatic | Tiny Volt If you let AI do your writing, I will come to your house and kill you Why Do We Sleep Under Blankets, Even on the Hottest Nights? (2017) Companies Are Just a Graph of Algorithms The Eternal Sloptember AI is becoming increasingly unpopular Turmoil in San Francisco immigration court as judges fired, retired, or resigned | AP News
C64 BASIC: Game Map Overhead “Camera View”
2026-05-26 · via Hacker News: Front Page

Explanation of how to create an Ultima-style map view turns into an adventure in C64 BASIC optimisation

Games like Ultima have a classic overhead camera view rather than the moving character view that I have been showing in my retro roguelike. How is that implemented?

Jay in the Commodore 64 Ultimate Development & Modifications Facebook group asked:

Character Movement vs Map Movement.
Hopefully that makes sense. I have a map that it 40x24. I know how to code the character to move around the map. That’s the easy part. What I am looking for is more of keeping the character in the center and moving the map around the character. Think Ultima 3 where the map window is 11x11 and the character never strays from the center. When you move the map shifts. Does someone have a good sample app they would share the source code with. Trying to learn here.

Here is my answer (which on reflection wasn’t as helpful as it could have been):

The way to do it with c64 characters is the map defines the whole potential area and the “camera view” is a slice of that starting at x, y of the map.

So if the map is 100,100 you need x to x+11, for y to y+11 rows.

I’m sure someone has code already if not I can come back with some

Rather than leave that as it was, I felt I needed to offer a better solution, plus it is a good challenge to walk through in a blog post, so here we are.

View Port Versus Map

As I mention briefly in my response, the main mental split is between the “world map” and the visible portion. We are simulating a viewport or portal into the whole, and solutions will involve taking the correct slices out of the bigger version and pasting them onto the game screen.

  • Our player has a X and Y coordinate that represent their horizontal/left and vertical/top position in the world
  • The world map is the whole potential area living in memory, independent of who or what’s on screen this second
  • The playable area on screen is just a fixed size camera view, it’s a slice of the map starting at some (x, y) position within the whole
  • For a 100×100 map you only ever draw x to x+10 across and y to y+10 down (ie. 11 tiles each way for an 11×11 window)

Another wrinkle, of course, is however we draw it, we also want to center the gameplay on the player character, so there also needs to be an additional offset from the top, left, so the sprite or whatever is in the middle vertically and horizontally rather than always at the top left of our game screen.

You can now follow the tutorials and edit the code right in your web browser with the Online Retro IDE

– No downloads, configuration, etc necessary, and it is free!

First Draft, No Optimisation

Our dirty first draft, completely unoptomised, will be barely one step away from pseudocode:

  1. Define a 2D map array M(x, y) sized to the full world dimensions
  2. Track the player’s world position (PX, PY) separately from their screen position
  3. Each time through the game loop:
    • Compute the camera top-left: CX = PX - 5, CY = PY - 5 (half the 11×11 viewport)
    • Clamp the camera so it never reads off the edge of the map (Zelda style)
    • For each cell (I, J) in the 11×11 viewport, copy M(CX+I, CY+J) to screen RAM at (OX+I, OY+J)
    • Draw the player at the fixed screen centre (or offset, if the camera clamped)
    • Wait for input, update (PX, PY), redraw

Of course this is really really slow, but as a proof of concept it helps us get the general shape nailed.

Level 1 Code

 →Get your own editable copy of the final code and see it run in the online editor.

10 REM ---- LARGE MAP / SMALL CAMERA DEMO ----
20 REM JAY'S QUESTION: KEEP PLAYER CENTRED,
30 REM MOVE THE MAP AROUND THEM (ULTIMA STYLE)
40 REM LEVEL 1: HORRENDOUSLY SLOW UNOPTIMISED FIRST DRAFT
50 MW=40 : MH=24
60 VW=11 : VH=11
70 HX=INT(VW/2) : HY=INT(VH/2)
80 OX=14 : OY=6
90 SC=1024
100 DIM M(MW-1,MH-1)
110 GOSUB 600 : REM BUILD MAP
120 PX=20 : PY=12
130 PRINT CHR$(147)
140 GOSUB 300 : REM DRAW VIEWPORT
150 GOSUB 500 : REM DRAW PLAYER
160 GET K$ : IF K$="" THEN 160
170 DX=0 : DY=0
180 IF K$="W" THEN DY=-1
190 IF K$="S" THEN DY=1
200 IF K$="A" THEN DX=-1
210 IF K$="D" THEN DX=1
220 IF K$="Q" THEN PRINT CHR$(147) : END
230 NX=PX+DX : NY=PY+DY
240 IF NX<0 OR NX>MW-1 OR NY<0 OR NY>MH-1 THEN 160
250 PX=NX : PY=NY
260 GOSUB 300 : GOSUB 500 : GOTO 160
270 REM
300 REM ---- DRAW VIEWPORT (NAIVE) ----
310 CX=PX-HX : CY=PY-HY
320 IF CX<0 THEN CX=0
330 IF CY<0 THEN CY=0
340 IF CX>MW-VW THEN CX=MW-VW
350 IF CY>MH-VH THEN CY=MH-VH
360 FOR J=0 TO VH-1
370  FOR I=0 TO VW-1
380   POKE SC+(OY+J)*40+(OX+I),M(CX+I,CY+J)
390  NEXT I
400 NEXT J
410 RETURN
420 REM
500 REM ---- DRAW PLAYER (NAIVE) ----
510 SX=OX+(PX-CX) : SY=OY+(PY-CY)
520 POKE SC+SY*40+SX,81
530 RETURN
540 REM
600 REM ---- BUILD TEST MAP ----
610 FOR Y=0 TO MH-1
620  FOR X=0 TO MW-1
630   T=46
640   IF X=0 OR Y=0 OR X=MW-1 OR Y=MH-1 THEN T=160
650   IF (X=10 AND Y>4 AND Y<15) THEN T=160
660   IF (Y=8 AND X>14 AND X<25) THEN T=87
670   M(X,Y)=T
680  NEXT X
690 NEXT Y
700 RETURN

Phase 2: Screen Lookup Table (LUT)

We could leave it at the above but it animates like a slideshow rather than a game, plus you might be forgiven for thinking it has crashed due to the extreme slow startup. Let’s tweak the display logic first.

The biggest move we can make at this stage is to replace the expensive multiplication (OY+J)*40 with a precomputed lookup table. Our 8 bit 6510 is not quick at multiplication as a rule, even less nimble in floating point BASIC. So we add DIM R(24) and fill once at startup: FOR Y = 0 TO 24 : R(Y) = Y*40 : NEXT Y

The display loop then becomes one lookup, no multiply:

RO = SC + R(OY+J) + OX

POKE RO+I, M(CX+I, CY+J)

121 floating-point multiplications eliminated! ~3–5× faster.

This will unfortunately make the startup even slower.

Phase 3: Dual Lookup Tables

Why is it still slow? 2D array access in BASIC v2 still costs a hidden multiply per read.

So how about we switch the map to a flat 1D array: DIM M(MW*MH - 1)

Now due to this change we should add a map-row lookup table: DIM MR(MH-1) and fill that LUT with MR(Y) = Y * MW at startup.

Our viewport loop now has become ONLY additions, which microprocessors are much better at:

  • RO = SC + R(OY+J) + OX (screen base for the row)
  • MO = MR(CY+J) + CX (map base for the row)
  • POKE RO+I, M(MO+I) zero multiplies

Again, we trade off play speed with initialisation delays – we have added ~24 more multiplications at startup, but we did eliminate ~121+ per display frame.

Phase 4: Init Progress Indicator

We started out with a slow startup but it is now so slow that if we don’t show the program is running it is certain to look frozen.

All we need to do is print inside each initialisation loop.Ironically those prints do add even more slowness to the process, C64 BASIC is not at all quick at printing.

Fortunately in a real game we would encode the LUTs and map as DATA statements and READ them, or even better load from disk.

Phase 5: Unrolled Loop

The last stage of optmisation is to find the next “Hot Path” and optimise it.

A “hot path” is the section of your program that is executed most frequently. Optimising those sections provide the most noticeable improvements.

In this case our FOR J = 0 TO 10 ... NEXT J runs every redraw with the same constant bounds.

BASIC’s FOR/NEXT per-iteration overhead is significant (push to the stack, perform variable lookup, do a comparison, jump to next).

Instead we can move the calculation to another LUT DIM VR(10) filled with VR(J) = SC + R(OY+J) + OX once at startup and “unroll” one of the loops. Instead of two FOR loops we replace the outer loop with 11 explicit lines that each handle outputting one row:

RO = VR(0) : MO = MR(CY) + CX : GOSUB 460

RO = VR(1) : MO = MR(CY+1) + CX : GOSUB 460

Yeah, we still have a FOR but we have eliminated 10 NEXT s per display frame which is not too shabby.

It does feel snappier on each WASD press which is a big deal.

Final Code (for now)

 →Get your own editable copy of the final code and see it run in the online editor.

Further optimisation ideas follow, but here is a good place to end with some working but still too slow code.

10 REM ---- LARGE MAP / SMALL CAMERA DEMO ----
20 REM JAY'S QUESTION: KEEP PLAYER CENTRED,
30 REM MOVE THE MAP AROUND THEM (ULTIMA STYLE)
40 REM LEVEL 3: UNROLLED VIEWPORT + PRECOMPUTED
50 MW=40 : MH=24
60 VW=11 : VH=11
70 HX=INT(VW/2) : HY=INT(VH/2)
80 OX=14 : OY=6
90 SC=1024
95 PRINT CHR$(147) : PRINT "LOADING";
100 DIM M(MW*MH-1)
105 DIM R(24)
106 DIM MR(MH-1)
107 DIM VR(10)         : REM PRE-BAKED VIEWPORT ROW SCREEN BASES
110 FOR Y=0 TO 24 : R(Y)=Y*40 : PRINT "."; : NEXT Y
111 FOR Y=0 TO MH-1 : MR(Y)=Y*MW : PRINT "."; : NEXT Y
112 FOR J=0 TO 10 : VR(J)=SC+R(OY+J)+OX : NEXT J
113 PRINT : PRINT "BUILDING MAP";
114 GOSUB 600
115 PRINT : PRINT "READY"
120 PX=20 : PY=12
130 PRINT CHR$(147)
140 GOSUB 300
150 GOSUB 500
160 GET K$ : IF K$="" THEN 160
170 DX=0 : DY=0
180 IF K$="W" THEN DY=-1
190 IF K$="S" THEN DY=1
200 IF K$="A" THEN DX=-1
210 IF K$="D" THEN DX=1
220 IF K$="Q" THEN PRINT CHR$(147) : END
230 NX=PX+DX : NY=PY+DY
240 IF NX<0 OR NX>MW-1 OR NY<0 OR NY>MH-1 THEN 160
250 PX=NX : PY=NY
260 GOSUB 300 : GOSUB 500 : GOTO 160
270 REM
300 REM ---- DRAW VIEWPORT (UNROLLED, LUT) ----
310 CX=PX-HX : CY=PY-HY
320 IF CX<0 THEN CX=0
330 IF CY<0 THEN CY=0
340 IF CX>MW-VW THEN CX=MW-VW
350 IF CY>MH-VH THEN CY=MH-VH
360 RO=VR(0) : MO=MR(CY)+CX     : GOSUB 460
361 RO=VR(1) : MO=MR(CY+1)+CX   : GOSUB 460
362 RO=VR(2) : MO=MR(CY+2)+CX   : GOSUB 460
363 RO=VR(3) : MO=MR(CY+3)+CX   : GOSUB 460
364 RO=VR(4) : MO=MR(CY+4)+CX   : GOSUB 460
365 RO=VR(5) : MO=MR(CY+5)+CX   : GOSUB 460
366 RO=VR(6) : MO=MR(CY+6)+CX   : GOSUB 460
367 RO=VR(7) : MO=MR(CY+7)+CX   : GOSUB 460
368 RO=VR(8) : MO=MR(CY+8)+CX   : GOSUB 460
369 RO=VR(9) : MO=MR(CY+9)+CX   : GOSUB 460
370 RO=VR(10) : MO=MR(CY+10)+CX : GOSUB 460
410 LX=CX : LY=CY
420 RETURN
430 REM
460 REM ---- POKE ONE VIEWPORT ROW ----
470 FOR I=0 TO 10 : POKE RO+I, M(MO+I) : NEXT I
480 RETURN
490 REM
500 REM ---- DRAW PLAYER ----
510 SX=OX + (PX-LX)
520 SY=OY + (PY-LY)
530 POKE SC+R(SY)+SX, 81
540 RETURN
550 REM
600 REM ---- BUILD TEST MAP ----
620 FOR Y=0 TO MH-1
625  YB=MR(Y) : PRINT ".";
630  FOR X=0 TO MW-1
640   T=46
650   IF X=0 OR Y=0 OR X=MW-1 OR Y=MH-1 THEN T=160
660   IF (X=10 AND Y>4 AND Y<15) THEN T=160
670   IF (Y=8 AND X>14 AND X<25) THEN T=87
675   M(YB+X)=T
680  NEXT X
690 NEXT Y
700 RETURN

Ideas for future optimisations

So about those future optimisation ideas …

1. PRINT is faster than POKE

The biggest would be to eliminate the slow pokes (heh). We have seen before that in C64 BASIC with no assembly routines, print is faster than poke. POKEing individual characters to screen memory is slow. PRINTing with the cursor positioned via cursor escape controls would be the single biggest remaining win in pure BASIC.

Building up the string using concatenation would still be slow so instead the map would be built as a string array of rows I think. We could use C64 BASIC string manipulation commands to extract just the portions we need.

2. ASM Routines Called from BASIC

Alternatively, or in addition, we could have an assembly routine that does the display and uses memory copies. This would bypass our display loops and character by character friction and instead would be given a starting memory address and would get the source and paste to the destination super quick.

3. Meta Tiles

Bitmap brothers pixel art is a huge inspiration for me. See the meta tiles in Chaos Engine to great effect
Great use of Meta Tiles in Bitmap Brothers’ – Chaos Engine

Last thought I had was to use meta-tiles. Part of the reason initialisation is so slow is because the map is made up character by character, but in a game like Ultima or Zelda you might use tiles that are 3×3 or 5×5 to make a wall corner, part of a house, a bend in a road, and so on. This would make loading or generating the world map a lot quicker because it could be the same size when displayed but compressed down to 1/3 or smaller.

Other improvements:

How else would I improve it?

  • Colour: parallel POKEs into $D800 (55296) so walls are grey, water is blue, grass is green, player is yellow …
  • Partial redraw: when moving one tile you only need to draw the newly-revealed row or column plus the old/new player position ~12 characters instead of 121, so roughly 10× faster.
  • Hardware smooth scroll: writing to $D016 / $D011 for sub-character pixel scrolling.
  • Custom character set: replace the default font with bespoke tile graphics for a real game polish.

Lessons Learned

The technique that started this discussion applies no matter what platform or language you are using. Decouple your world coords from the visible screen coords and treat the playable, visible area as a window into a larger ‘world’ buffer. While my ‘Zelda-Like‘ demos use push scrolling, the concept used is the same.

We quickly went into a side-quest of trying to get CBM BASIC v2 to perform. The cost of multiplications in particular was very visible.

Lookup tables are the single most powerful optimisation tool on retro systems: trade a tiny bit of RAM and up-front calculations for huge time savings at runtime. You can see this technique over and over in the demo scene.

Finally, unroll loops (and anything else you need to do), but don’t optimise until you’ve measured where your hold-ups are (your hot path). As in the linked video from Robin, just because something seems like it should make things faster, doesn’t mean it will!