Skip to content

Instantly share code, notes, and snippets.

@Bananattack
Last active Aug 24, 2021
Embed
What would you like to do?
entity_move.wiz
namespace entity {
in ram {
let COUNT = 32;
var data : [Entity; COUNT];
namespace move_flags {
namespace bit {
let COLLIDED_X = 0;
let COLLIDED_Y = 1;
let NUDGE = 6;
let IGNORE_BOUNDS = 7;
}
namespace mask {
let NONE = 0x00;
let COLLIDED_X = 0x01;
let COLLIDED_Y = 0x02;
let NUDGE = 0x40;
let IGNORE_BOUNDS = 0x80;
}
}
let HITBOX_X = 2;
let HITBOX_X2 = 13;
let HITBOX_Y = 1;
let HITBOX_Y2 = 15;
}
// ...
func move(ent : *Entity in ix, x_speed : u8 in b0, y_speed : u8 in b1, flags : u8 in b) : u8 in b {
a = x_speed;
// TODO: Handle entity hitscan collisions.
// or simply set collision tiles behind enemies?
^if a != 0 {
// Sign extend speed to 16.8
l = a;
d = 0;
if l$7 {
d--;
}
c = d;
// Convert speed from 4.4 to 16.8.
// (upper byte won't be affected)
inline for in 1 .. 4 {
a <<= 1;
d <<<<#= 1;
}
// Add 16.8 speed to 16.8 entity position.
var temp_subpixel_x : u8 in e = a = a + <:ent.x;
var temp_pixel_x : u8 in d = a = d +# >:ent.x;
var temp_screen_x : u8 in c = a = c +# #:ent.x;
push(de);
push(af);
if l$7 {
temp_pixel_x = a = temp_pixel_x + HITBOX_X;
temp_screen_x = a = temp_screen_x +# 0;
} else {
temp_pixel_x = a = temp_pixel_x +# HITBOX_X2;
temp_screen_x = a = temp_screen_x +# 0;
}
// If not on the current screen, we're out of bounds.
if {
l = a = room_screen_x;
a = temp_screen_x;
} && a != l {
^goto success if flags$move_flags.bit.IGNORE_BOUNDS;
// Less than current screen? clamp to left edge.
if a$7 || a < l {
<:ent.x = a = 0;
>:ent.x = a = 256 - HITBOX_X;
l--;
// Greater than current screen? clamp to right edge.
} else if { a++; } && a >= l {
<:ent.x = a = 0;
>:ent.x = a = ROOM_TILEMAP_WIDTH * 16 - HITBOX_X2;
}
#:ent.x = a = l;
flags$move_flags.bit.COLLIDED_X = true;
^goto failure;
}
l = a = room_screen_y;
a = #:ent.y;
if a$7 || a < l {
h = l = 0;
} else if zero {
a = >:ent.y + HITBOX_Y;
if carry || a >= ROOM_TILEMAP_HEIGHT * 16 {
h = l = (ROOM_TILEMAP_HEIGHT - 1) * 16;
} else {
l = a = a & 0xF0;
a = >:ent.y + HITBOX_Y2;
if carry || a >= ROOM_TILEMAP_HEIGHT * 16 {
a = (ROOM_TILEMAP_HEIGHT - 1) * 16;
} else {
a = a & 0xF0;
}
h = a;
}
} else {
h = l = (ROOM_TILEMAP_HEIGHT - 1) * 16;
}
push(hl);
// Calculate top tile coord.
a = (temp_pixel_x >>> 4) | l;
// Get tile at top.
var ptr : *u8 in hl = &room_tilemap[0];
<:ptr = a = a + <:ptr;
>:ptr = a = >:ptr +# 0;
a = *ptr;
// Get collision info.
ptr = &tileset.flags_data[0];
<:ptr = a = a + <:ptr;
>:ptr = a = >:ptr +# 0;
// Check collision.
if { a = (tileset.flags.mask.PIT | tileset.flags.mask.WALL) & *ptr; } && !zero {
// Snap to closest x.
<:ent.x = a = <:ent.x & 0xF0;
flags$move_flags.bit.COLLIDED_X = true;
}
// Calculate bottom tile coord.
hl = pop();
a = (temp_pixel_x >>> 4) | h;
// Get tile at bottom
ptr = &room_tilemap[0];
<:ptr = a = a + <:ptr;
>:ptr = a = >:ptr +# 0;
a = *ptr;
// Get collision info.
ptr = &tileset.flags_data[0];
<:ptr = a = a + <:ptr;
>:ptr = a = >:ptr +# 0;
// Check collision.
if { a = (tileset.flags.mask.PIT | tileset.flags.mask.WALL) & *ptr; } && !zero {
// Snap to closest x.
<:ent.x = a = <:ent.x & 0xF0;
// We collided below. If we're nudging, but didn't collide above, nudge up.
if { a = flags & (move_flags.mask.COLLIDED_X | move_flags.mask.NUDGE); } && a == move_flags.mask.NUDGE
&& { a = y_speed; } && a == 0 {
af = pop();
de = pop();
ptr = &x_speed;
*ptr++ = 0;
*ptr++ = -0x10 as u8;
flags = a = flags & move_flags.mask.IGNORE_BOUNDS;
^return move(ent, x_speed, y_speed, flags);
}
flags$move_flags.bit.COLLIDED_X = true;
}
// We didn't collide below. If we're nudging, and we collided above, nudge down.
else if { a = flags & (move_flags.mask.COLLIDED_X | move_flags.mask.NUDGE); } && a == (move_flags.mask.COLLIDED_X | move_flags.mask.NUDGE)
&& { a = y_speed; } && a == 0 {
af = pop();
de = pop();
ptr = &x_speed;
*ptr++ = 0;
*ptr++ = 0x10;
flags = a = flags & move_flags.mask.IGNORE_BOUNDS;
^return move(ent, x_speed, y_speed, flags);
}
goto failure if flags$move_flags.bit.COLLIDED_X;
success: {
af = pop();
de = pop();
<:ent.x = temp_subpixel_x;
>:ent.x = temp_pixel_x;
#:ent.x = a;
goto done;
}
failure: {
af = pop();
de = pop();
}
done:
}
a = y_speed;
^if a != 0 {
// Sign extend speed to 16.8
l = a;
d = 0;
if l$7 {
d--;
}
c = d;
// Convert speed from 4.4 to 16.8.
// (upper byte won't be affected)
inline for in 1 .. 4 {
a <<= 1;
d <<<<#= 1;
}
// Add 16.8 speed to 16.8 entity position.
var temp_subpixel_y : u8 in e = a = a + <:ent.y;
var temp_pixel_y : u8 in d = a = d +# >:ent.y;
var temp_screen_y : u8 in c = a = c +# #:ent.y;
push(de);
push(af);
if l$7 {
temp_pixel_y = a = temp_pixel_y + HITBOX_Y;
temp_screen_y = a = temp_screen_y +# 0;
} else {
temp_pixel_y = a = temp_pixel_y +# HITBOX_Y2;
temp_screen_y = a = temp_screen_y +# 0;
}
// If not on the current screen, we're out of bounds.
if {
l = a = room_screen_y;
a = temp_screen_y;
} && a != l {
^goto success if flags$move_flags.bit.IGNORE_BOUNDS;
// Less than current screen? clamp to left edge.
if a$7 || a < l {
<:ent.y = a = 0;
>:ent.y = a = 256 - HITBOX_Y;
l--;
// Greater than current screen? clamp to right edge.
} else if { a++; } && a >= l {
<:ent.y = a = 0;
>:ent.y = a = ROOM_TILEMAP_HEIGHT * 16 - HITBOX_Y2;
}
#:ent.y = a = l;
flags$move_flags.bit.COLLIDED_Y = true;
^goto failure;
} else if {
l = a = ROOM_TILEMAP_HEIGHT * 16;
a = temp_pixel_y;
} && a >= l {
^goto success if flags$move_flags.bit.IGNORE_BOUNDS;
<:ent.y = a = 0;
>:ent.y = a = ROOM_TILEMAP_HEIGHT * 16 - HITBOX_Y2;
flags$move_flags.bit.COLLIDED_Y = true;
^goto failure;
}
l = a = room_screen_x;
a = #:ent.x;
if a$7 || a < l {
h = l = 0;
} else if zero {
a = >:ent.x + HITBOX_X;
if carry {
h = l = ROOM_TILEMAP_WIDTH - 1;
} else {
a >>>= 4;
l = a;
a = >:ent.x + HITBOX_X2;
if carry {
a = ROOM_TILEMAP_WIDTH - 1;
} else {
a >>>= 4;
}
h = a;
}
} else {
h = l = ROOM_TILEMAP_WIDTH - 1;
}
push(hl);
// Calculate left tile coord.
a = (temp_pixel_y & 0xF0) | l;
// Get tile at left.
var ptr : *u8 in hl = &room_tilemap[0];
<:ptr = a = a + <:ptr;
>:ptr = a = >:ptr +# 0;
a = *ptr;
// Get collision info.
ptr = &tileset.flags_data[0];
<:ptr = a = a + <:ptr;
>:ptr = a = >:ptr +# 0;
// Check collision.
if { a = (tileset.flags.mask.PIT | tileset.flags.mask.WALL) & *ptr; } && !zero {
// Snap to closest y.
<:ent.y = a = <:ent.y & 0xF0;
flags$move_flags.bit.COLLIDED_Y = true;
}
// Calculate right tile coord.
hl = pop();
a = (temp_pixel_y & 0xF0) | h;
// Get tile at right.
ptr = &room_tilemap[0];
<:ptr = a = a + <:ptr;
>:ptr = a = >:ptr +# 0;
a = *ptr;
// Get collision info.
ptr = &tileset.flags_data[0];
<:ptr = a = a + <:ptr;
>:ptr = a = >:ptr +# 0;
// Check collision.
if { a = (tileset.flags.mask.PIT | tileset.flags.mask.WALL) & *ptr; } && !zero {
// Snap to closest y.
<:ent.y = a = <:ent.y & 0xF0;
// We collided on the right. If we're nudging, but didn't collide on the left, nudge left.
if { a = flags & (move_flags.mask.COLLIDED_Y | move_flags.mask.NUDGE); } && a == move_flags.mask.NUDGE
&& { a = x_speed; } && a == 0 {
af = pop();
de = pop();
ptr = &x_speed;
*ptr++ = -0x10 as u8;
*ptr++ = 0;
flags = a = flags & move_flags.mask.IGNORE_BOUNDS;
^return move(ent, x_speed, y_speed, flags);
}
flags$move_flags.bit.COLLIDED_Y = true;
}
// We didn't collide on the right. If we're nudging, and we collided on the left, nudge right.
else if { a = flags & (move_flags.mask.COLLIDED_Y | move_flags.mask.NUDGE); } && a == (move_flags.mask.COLLIDED_Y | move_flags.mask.NUDGE)
&& { a = x_speed; } && a == 0 {
af = pop();
de = pop();
ptr = &x_speed;
*ptr++ = 0x10;
*ptr++ = 0;
flags = a = flags & move_flags.mask.IGNORE_BOUNDS;
^return move(ent, x_speed, y_speed, flags);
}
goto failure if flags$move_flags.bit.COLLIDED_Y;
success: {
af = pop();
de = pop();
<:ent.y = temp_subpixel_y;
>:ent.y = temp_pixel_y;
#:ent.y = a;
goto done;
}
failure: {
af = pop();
de = pop();
}
done:
}
return flags;
}
}
@lhsazevedo
Copy link

lhsazevedo commented Mar 13, 2021

*Entity in ix ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment