Untitled adventure game, Milestone 2: Basic gameplay

A place where you can keep others updated about your NES-related projects through screenshots, videos or information in general.

Moderator: Moderators

User avatar
bleubleu
Posts: 108
Joined: Wed Apr 04, 2018 7:29 pm
Location: Montreal, Canada

Untitled adventure game, Milestone 2: Basic gameplay

Post by bleubleu »

Time for an update, trying a video format this time. Less work for me.

Image

-Mat
User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by FrankenGraphics »

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.
User avatar
samophlange
Posts: 50
Joined: Sun Apr 08, 2018 11:45 pm
Location: Southern California

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by samophlange »

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?
User avatar
darryl.revok
Posts: 520
Joined: Sat Jul 25, 2015 1:22 pm

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by darryl.revok »

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. :)
User avatar
bleubleu
Posts: 108
Joined: Wed Apr 04, 2018 7:29 pm
Location: Montreal, Canada

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by bleubleu »

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
User avatar
bleubleu
Posts: 108
Joined: Wed Apr 04, 2018 7:29 pm
Location: Montreal, Canada

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by bleubleu »

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
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by Banshaku »

Looks good. Will be interesting to see how it progress :D
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by calima »

The art reminds me of Pokemon.
User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by FrankenGraphics »

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. :)
SoleGooseProductions
Posts: 29
Joined: Mon Nov 11, 2013 2:23 pm

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by SoleGooseProductions »

Saw this over and Twitter and wanted to pop in to say WOW! Very nice graphics, and the rest looks solid as well!
User avatar
bleubleu
Posts: 108
Joined: Wed Apr 04, 2018 7:29 pm
Location: Montreal, Canada

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by bleubleu »

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
User avatar
bleubleu
Posts: 108
Joined: Wed Apr 04, 2018 7:29 pm
Location: Montreal, Canada

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by bleubleu »

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
User avatar
bleubleu
Posts: 108
Joined: Wed Apr 04, 2018 7:29 pm
Location: Montreal, Canada

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by bleubleu »

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: Select all

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: Select all

	; 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
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by tepples »

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.
User avatar
bleubleu
Posts: 108
Joined: Wed Apr 04, 2018 7:29 pm
Location: Montreal, Canada

Re: Untitled adventure game, Milestone 2: Basic gameplay

Post by bleubleu »

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
Post Reply