diff options
| author | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-04-01 21:19:45 +0200 |
|---|---|---|
| committer | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-04-02 21:23:51 +0200 |
| commit | 88728b89fed87326dae23619e2e93d4bd060a3ea (patch) | |
| tree | 4c1bf3af96e1e1ea200f9e5c08e3a672f5c4fe54 | |
| parent | 2f140cfb7ea73e631fce086327bcb3a674758b0e (diff) | |
| download | jetpac.nes-88728b89fed87326dae23619e2e93d4bd060a3ea.tar.gz jetpac.nes-88728b89fed87326dae23619e2e93d4bd060a3ea.zip | |
Adapt velocity constants for PAL
In 2f140cfb7ea7 ("player: First PAL implementation") the rate of
acceleration was adapted for PAL. Now the values for velocities have
been adapted as well, in a way that we get (virtually) the same
experience in PAL and in NTSC.
This has been done by moving the velocity constants into configurable
values, which are then picked up by a new bin/values.rb script. This
script allows us to write the constants in plain floating point numbers,
does the conversion to fixed point numbers as expected, and it also does
the same for PAL by applying the proper NTSC to PAL conversion.
As a cherry on top, some values have also been tuned to match the
original game more closely, even if some more fine tuning might still be
needed here and there.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
| -rw-r--r-- | .editorconfig | 4 | ||||
| -rw-r--r-- | CONTRIBUTING.md | 20 | ||||
| -rw-r--r-- | Makefile | 24 | ||||
| -rw-r--r-- | README.md | 4 | ||||
| -rw-r--r-- | bin/values.rb | 80 | ||||
| -rw-r--r-- | config/values.yml | 30 | ||||
| -rw-r--r-- | config/values/player.s | 28 | ||||
| -rw-r--r-- | src/player.s | 22 |
8 files changed, 193 insertions, 19 deletions
diff --git a/.editorconfig b/.editorconfig index c420a82..bd627cd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,5 +9,9 @@ end_of_line = lf [*.{s,S}] indent_style = space +[*.rb] +indent_size = 2 +indent_style = space + [Makefile] indent_style = tab diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c70602d..215034b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,8 +1,10 @@ ## Why? -Do you want to fix an error you have found? Do you know a way to improve my -6502-fu or do you know a technique on NES/Famicom development that might help -here? I am open for discussion and welcome any help! +- You want to make a suggestion on something that could be improved. +- You want to report a bug, something that doesn't work as expected. +- You know of a sick 6502 assembly technique that could be applied. + +I am open for discussion and welcome any help! ## How? @@ -35,6 +37,18 @@ In order to test your changes, I'd go this way: 3. Run the ROM that was produced with an emulator of your choosing. Make sure that things run as expected. +### Customizing the build process + +You can pass the following arguments to `make`: + +- `CC65`: the compiler to use (defaults to `cl65`). +- `CCOPTS`: the options to use for the compiler (defaults to `--target nes`). +- `RUBY`: the ruby to use (defaults to `ruby`). + +Note that you can also set `DEBUG=1`, and with that you will pass sobre extra +debugging options, like telling `cl65` to also output a `out/labels.txt` file +with memory address on the symbols that have been evaluated. + ## Modifying assets I am using [NEXXT studio 3](https://frankengraphics.itch.io/nexxt) for managing @@ -7,12 +7,23 @@ else Q = endif +# NOTE: you can configure `CC65` and `CCOPTS` with the compiler and its options +# that you might require. Moreover, if you pass `DEBUG` to `make`, then an +# `out/labels.txt` file will be generated. CC65 ?= cl65 CCOPTS ?= --target nes ifeq "$(DEBUG)" "1" CCOPTS += -g -Ln out/labels.txt endif +# Ruby is used to generate the files on `config/values/`. If it can't be found, +# a warning will be echo'ed. +# +# NOTE: you can actually set RUBY as an argument to `make` if you want to pass +# something special to it. +RUBY ?= ruby +HAS_RUBY := $(shell command -v $(RUBY) >/dev/null 2>&1 && echo true || echo false) + .PHONY: all all: clean deps build @@ -25,10 +36,19 @@ clean: .PHONY: deps deps: - @which $(CC65) >/dev/null 2>/dev/null || (echo "ERROR: $(CC65) not found." && false) + @which $(CC65) >/dev/null 2>/dev/null || (echo "ERROR: '$(CC65)' not found." && false) + +.PHONY: gen-values +gen-values: +ifeq ($(HAS_RUBY),true) + $(E) " GEN config/values" + $(Q) ruby bin/values.rb +else + @(Q) echo "WARNING: '$(RUBY)' not found; files under 'config/values/' will not be generated." +endif .PHONY: build -build: build-full build-partial build-pal +build: gen-values build-full build-partial build-pal .PHONY: build-full build-full: @@ -1,7 +1,9 @@ This is a port to the NES/Famicom of the renown [jetpac](https://en.wikipedia.org/wiki/Jetpac) game from Ultimate Play the Game. You can find a ROM to play the game in the [releases -page](https://github.com/mssola/jetpac.nes/releases). +page](https://github.com/mssola/jetpac.nes/releases). Read the +[CONTRIBUTING.md](./CONTRIBUTING.md) file if you want to make any changes, +report an issue or make a suggestion. ## The game diff --git a/bin/values.rb b/bin/values.rb new file mode 100644 index 0000000..3ff1578 --- /dev/null +++ b/bin/values.rb @@ -0,0 +1,80 @@ +#!/usr/bin/env ruby + +## +# Generate the different values on `config/values/*.s` by parsing the values on +# `config/values.yml`. The values on that file are agnostic to NTSC or PAL, and +# it's up to this script to produce constants which make sense for NTSC and PAL. +# That is, it's a way to ensure that both NTSC and PAL have the same experience +# (or at least as close as possible). + +## +# Parse the configuration. + +require 'yaml' + +config_path = File.join("#{File.dirname(__FILE__)}/..", 'config/') +config = YAML.safe_load_file(File.join(config_path, 'values.yml')) + +# Converts the given floating point value into a signed fixed point value in the +# 4.4 format. +def to_signed_fixed_point(value) + integer = value.to_i + raise "bad signed fixed point value" if integer > 7 || integer < -7 + integer &= 0b00001111 + + decimal = (value % 1) * 100 + decimal = ((decimal * 15) / 100.0).round & 0b00001111 + + (integer << 4) | decimal +end + +## +# Loop through the configuration and fetch values for NTSC and PAL. + +res = {} +config.each do |model, properties| + res[model] ||= { ntsc: {}, pal: {} } + + properties.each do |name, ntsc| + name = name.upcase + pal = (ntsc * 6) / 5.0 + + res[model][:ntsc][name] = to_signed_fixed_point(ntsc) + res[model][:pal][name] = to_signed_fixed_point(pal) + end +end + +## +# Generate each model as expected. + +def to_hex(value) + hex = value.to_s(16).upcase + + if hex.size == 1 + "$0#{hex}" + else + "$#{hex}" + end +end + +def values_to_asm(values) + contents = "" + values.each { |k, v| contents << " #{k} = #{to_hex(v)}\n" } + contents.rstrip +end + +res.each do |model, formats| + path = File.join(config_path, "values/#{model}.s") + contents = <<HERE +;; This file has been automatically generated via bin/values.rb. +;; DO NOT MODIFY this file directly: check config/values.yml instead. + +.ifdef PAL +#{values_to_asm(formats[:pal])} +.else +#{values_to_asm(formats[:ntsc])} +.endif +HERE + + File.open(path, 'w') { |f| f.write(contents) } +end diff --git a/config/values.yml b/config/values.yml new file mode 100644 index 0000000..257282e --- /dev/null +++ b/config/values.yml @@ -0,0 +1,30 @@ +# Constants used throughout the game in a floating point format. The +# `bin/values.rb` script will make sure to transform these into 4.4 signed fixed +# point values that fit into a byte, as expected by the code from this game. +# +# Each file will have the name of the key from the first level (e.g. "player" +# will become "config/values/player.s"), and under the file each constant will +# be upper cased (e.g. "player.throttle_up" will become "THROTTLE_UP" inside of +# the "player.s" file). + +player: + # Gravity and initial velocity when throttling from the ground. + gravity: 2.50 + blast_off: -1.50 + + # Throttling. + throttle_up: -2.90 + throttle_left: -2.90 + throttle_right: 1.90 + + # Walking constant velocities. + walk_left: -1.80 + walk_right: 0.80 + + # Horizontal bounces + bounce_left: -2.53 + bounce_right: 1.53 + + # Vertical bounces + reduce_full_speed: 1.00 + reduce_mid_speed: 0.53 diff --git a/config/values/player.s b/config/values/player.s new file mode 100644 index 0000000..a27d10a --- /dev/null +++ b/config/values/player.s @@ -0,0 +1,28 @@ +;; This file has been automatically generated via bin/values.rb. +;; DO NOT MODIFY this file directly: check config/values.yml instead. + +.ifdef PAL + GRAVITY = $30 + BLAST_OFF = $F3 + THROTTLE_UP = $D8 + THROTTLE_LEFT = $D8 + THROTTLE_RIGHT = $24 + WALK_LEFT = $ED + WALK_RIGHT = $0E + BOUNCE_LEFT = $DE + BOUNCE_RIGHT = $1D + REDUCE_FULL_SPEED = $13 + REDUCE_MID_SPEED = $0A +.else + GRAVITY = $28 + BLAST_OFF = $F8 + THROTTLE_UP = $E2 + THROTTLE_LEFT = $E2 + THROTTLE_RIGHT = $1D + WALK_LEFT = $F3 + WALK_RIGHT = $0C + BOUNCE_LEFT = $E7 + BOUNCE_RIGHT = $18 + REDUCE_FULL_SPEED = $10 + REDUCE_MID_SPEED = $08 +.endif diff --git a/src/player.s b/src/player.s index 9cb73f3..ebf6dfb 100644 --- a/src/player.s +++ b/src/player.s @@ -62,19 +62,15 @@ INIT_Y_POSITION_LO = ((Background::GROUND_Y_COORD - PLAYER_HEIGHT) & $0F) << 4 INIT_Y_POSITION_HI = (Background::GROUND_Y_COORD - PLAYER_HEIGHT) >> 4 - ;; The initial position on the X axis is more or less at the center. + ;; The initial position on the X axis is right below the mid platform. INIT_X_POSITION_LO = $00 - INIT_X_POSITION_HI = $07 + INIT_X_POSITION_HI = $08 ;; Different acceleration/velocity constants. - GRAVITY = $28 - THROTTLE_UP = $D8 - THROTTLE_LEFT = $D8 - THROTTLE_RIGHT = $28 - BLAST_OFF = $F8 ; Initial velocity from ground. - WALK_LEFT = $F8 - WALK_RIGHT = $08 - REDUCE_FULL_SPEED = $10 ; Next velocity after hitting a ceiling at full speed. + ;; + ;; NOTE: automatically generated via `bin/values.rb`. Check the + ;; `config/values.yml` to understand the meaning of each constant. + .include "../config/values/player.s" zp_screen_y = $40 zp_position_y = $41 ; NOTE: 16-bit. @@ -553,7 +549,7 @@ lda #REDUCE_FULL_SPEED bne @correct_vertical_velocity @reduced_velocity: - lda #8 + lda #REDUCE_MID_SPEED @correct_vertical_velocity: sta zp_velocity_y rts @@ -639,7 +635,7 @@ ;; game did. sec sbc #PLAYER_WIDTH - ldx #$E8 + ldx #BOUNCE_LEFT bne @horizontal_eject @left_collision: @@ -647,7 +643,7 @@ ;; need to add the tile width to it. clc adc #8 - ldx #$18 + ldx #BOUNCE_RIGHT @horizontal_eject: ;; The screen coordinate has been computed into the `a` register, and |
