Untitled adventure game, Milestone 2: Basic gameplay

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Untitled adventure game, Milestone 2: Basic gameplay
by on (#234550)
Time for an update, trying a video format this time. Less work for me.

Image

-Mat
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234551)
Love the demo! Nice mechanics, it's evident you've spent lots of care. thanks for showcasing. :beer: Also interesting to see how you've implemented stuff and how you ease editing with a basic-like syntax where practical.
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234568)
Wow, that looks absolutely fantastic. The asset too looks very versatile and easy to use, and its really neat how it allows you to visualize occluders, collision, etc. I'm impressed with how much gameplay you're able to create via scripting. :beer:
How did you add support for copy/paste from Aseprite?
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234569)
Hey there!

I'm still watching the video now but I wanted to chime in, that if you did these graphics yourself, then they're definitely good enough.

I understand if you just don't have the time to do all of the graphics, or if these are place-holder graphics from another source. But people can tend to be harder on their own work than that of others, and I wouldn't exclude these graphics from use for reasons of quality.

The graphics in this work-in-progress are definitely better than average for commercially released NES games. If they're something that you just ripped from another source then I apologize for the misplaced compliment. :)
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234580)
samophlange wrote:
How did you add support for copy/paste from Aseprite?


Thanks for the kind words. Aseprite is open source, so it is quite easy to see how the "encode" their clipboard data. I can send you my C# code if you want. It is essentially a bunch of image data, compressed using a DEFLATE type algorithm. Super simple. My "convention" when working in aseprite is that color 0 is transparent, 1,2,3 is the first palette, 4,5,6 is the 2nd, and so on.

-Mat
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234581)
darryl.revok wrote:
The graphics in this work-in-progress are definitely better than average for commercially released NES games. If they're something that you just ripped from another source then I apologize for the misplaced compliment. :)


Thanks. They are, in fact, heavily inspired by a bunch of stuff I found on google images, pinterest, etc. But most of the stuff you find online uses way too many colors to fit on the NES. So even when you want to "steal" stuff, it takes a lot of work to make it look nice.

-Mat
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234584)
Looks good. Will be interesting to see how it progress :D
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234591)
The art reminds me of Pokemon.
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234601)
yeah i forgot to comment about the graphics, but those are nice - i especially liked the walking animation for the patrolling bug, it has lots of nice character to it. :)
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234609)
Saw this over and Twitter and wanted to pop in to say WOW! Very nice graphics, and the rest looks solid as well!
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234645)
FrankenGraphics wrote:
yeah i forgot to comment about the graphics, but those are nice - i especially liked the walking animation for the patrolling bug, it has lots of nice character to it. :)


Ha thanks man.

SoleGooseProductions wrote:
Saw this over and Twitter and wanted to pop in to say WOW! Very nice graphics, and the rest looks solid as well!


Lol, one of my 3 followers. Hahah. Baby steps i guess. Thanks for the support man.

-Mat
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234652)
I love it, I love the graphics too. Can you provide more details on the code generation of your script language?
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234657)
yaros wrote:
I love it, I love the graphics too. Can you provide more details on the code generation of your script language?

Sure. I was looking for simplest language to implement and i remembered BASIC, which is the 1st language i learned as a kid (im old).

I drew inspiration from ubasic (https://github.com/adamdunkels/ubasic), which is a very small BASIC interpreter. But I essentially re-wrote the whole thing in C#, which is what my tools are written it, and converted it into a compiler, instead of an interpreter. I made up the bytecode. I support stuff like math operation, test conditions, jumps, loops, etc. I also support calling "engine functions". The engine in ASM can expose functions that can be called from the script, using a well defined calling convention. Also, the script can implement a certain number of entry points (or events) which are all the "on_xxx" functions. These are called by the assemble code when stuff happens.

In assembly, bytecode is implemented as a simple jump table. each opcode will fetch the arguments it needs and do whatever it needs to do. I allocate a small "heap" of 32-byte for the script. This includes global variable, local variables, temporary variables. Temporary variables are needed for things like "4 + (2 + 3)". Behind the scene temporary variables will be allocated to hold temporary results of the addition. This is all done at compile time.

That's about it really, its <1000 lines of ASM, a bit more on the tool side. But it really opens up the possibilities for prototyping ideas.

-Mat
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234694)
bleubleu wrote:
In assembly, bytecode is implemented as a simple jump table. each opcode will fetch the arguments it needs and do whatever it needs to do. I allocate a small "heap" of 32-byte for the script. This includes global variable, local variables, temporary variables. Temporary variables are needed for things like "4 + (2 + 3)". Behind the scene temporary variables will be allocated to hold temporary results of the addition. This is all done at compile time.


I am able to write simple parser, lexer or interpreter. When it comes to bytecode/machine code generation my brain shuts down. Could you advise some resources you used and learned from?
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234724)
yaros wrote:
I am able to write simple parser, lexer or interpreter. When it comes to bytecode/machine code generation my brain shuts down. Could you advise some resources you used and learned from?


Me too. I kind of made up the bytecode as I went along. Maybe the best way to go about it is with an example? This is an event that gets called when the player successfully hacks the keypad.

Code:
function on_game_event(event, param)
   if event = GAME_EVENT_KEYPAD_SUCCESS then
      set_timer(60)
   end if
end function


You can make your compiler simply generates the code as it parses (a real compiler would do multiple passes, use an intermediate representation to optimize more but we dont need that). You parse a statement (if, assignment, addition, etc.) and you output the bytes right away to an array. Sometimes, for jumps, you might need to patch some jump addresses and stuff, but for the most part, you can do it as you parse in one go.

This is the bytecode I use right now, and the disassembly next to it. There are generally two types of bytecode: stack based and register based, this is definitely register based.

The first byte is always the opcode.

Code:
   ; on_game_event
   .byte $0e, $01                 ;   0: get_arg0 event
   .byte $05, $01, $82            ;   2: compare_equal_byte event 0
   .byte $0a, $0a                 ;   5: jump_if_false 10
   .byte $13, $05, $8a            ;   7: invoke_r0 set_timer(60)
   .byte $1a                      ;  10: end


  • $0e = reads argument 0 passed from the engine, puts in variable slot $01 (i have 32 variable slots). Note that the compiler detected we never access the second argument, so it ignores it. Minor optimization.
  • $05 = equality comparison. Compares whatever is in variable $01 (what we just read) to constant $02 (when the minus bit, $80, is set, it means that its not a variable, but a constant stored in a table somewhere else. Whenever I encounter an hardcoded constant at compile-time, I look to see if I've seen it before and add it to that table if its new. Constants like "0" comes back quite often, so this is efficient).
  • $0a = jump to the location indicated (10, which is the end) if the last test condition was false. My conditional statements are optimized for "ORs of ANDs" (or "Disjunctive normal form" if you want to sound pretentious).
  • $13 = calls an engine function (engine function $05 is "set_timer") that takes a single argument and puts in in "r0" (a zero page variable in my engine), which is the constant table at location $0a.
  • $1a = end.

I hope this example can make it clear how easy it is to output this king of bytecode as you parse. Interpreting this is super easy, simple jump table, and a 32-byte array for your "RAM".

-Mat
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234727)
bleubleu wrote:
  • $0e = reads argument 0 passed from the engine, puts in variable slot $01 (i have 32 variable slots). Note that the compiler detected we never access the second argument, so it ignores it. Minor optimization.
  • $05 = equality comparison. Compares whatever is in variable $01 (what we just read) to constant $02 (when the minus bit, $80, is set, it means that its not a variable, but a constant stored in a table somewhere else. Whenever I encounter an hardcoded constant at compile-time, I look to see if I've seen it before and add it to that table if its new. Constants like "0" comes back quite often, so this is efficient).
  • $0a = jump to the location indicated (10, which is the end) if the last test condition was false. My conditional statements are optimized for "ORs of ANDs" (or "Disjunctive normal form" if you want to sound pretentious).
  • $13 = calls an engine function (engine function $05 is "set_timer") that takes a single argument and puts in in "r0" (a zero page variable in my engine), which is the constant table at location $0a.
  • $1a = end.

One thing that tripped me up while reading your "assembly language" in the comments to the right was that most architectures' equality comparison behaves as != instead of ==: a subtraction that is true if they are different or false if not. That way, the interpreter can use the same logic for compare and subtract.
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234728)
bleubleu wrote:
I hope this example can make it clear how easy it is to output this king of bytecode as you parse. Interpreting this is super easy, simple jump table, and a 32-byte array for your "RAM".


It does well, thank you.
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#234731)
tepples wrote:
One thing that tripped me up while reading your "assembly language" in the comments to the right was that most architectures' equality comparison behaves as != instead of ==: a subtraction that is true if they are different or false if not. That way, the interpreter can use the same logic for compare and subtract.


I see your point. But I really made it up as I went along. :) There was no masterplan, I didn't try to copy any existing architecture really.

Also, reusing the same opcodes for multiple things wasnt much of a concern. I favored large and very specific op-code that do a lot of things, as opposed to micro-ops that can be reused. The idea was to keep the bytecode compact, and have the ASM code be quite efficient. This mean that I probably have a lot more code in my interpreter, but that's ok.

-Mat
Re: Untitled adventure game, Milestone 2: Basic gameplay
by on (#239729)
WOW,

This looks absolutely fantastic. I love the art style, the black outlines, the blinking eyes on the sprite, shadows, color palettes. So many nice visual touches. Very impressive :)

Are you looking for music by chance?