Project1
标题: 复刻FC封神榜,如何实现类似跳跃的战斗移位?难题。。。 [打印本页]
作者: miantouchi 时间: 2019-6-15 15:28
标题: 复刻FC封神榜,如何实现类似跳跃的战斗移位?难题。。。
本帖最后由 miantouchi 于 2019-6-17 20:33 编辑
如何实现类似跳跃的战斗移位?
封神榜这个游戏战斗系统人物移动这块有点怪,既不是大多数的齐动画、也不是真移位
真移位,是图片平移过去,而这个游戏是战斗图片的跳跃,这要如何去实现呢?有没有什么现场的脚本算法改改也行。
神思、和熊式战斗,就是图片的匀速运动,我试了,图片平移很是生硬(并且移动路线是直线的)。齐动画也不是,这个游戏是各个角度的跳跃,然后落到,怪物面前去攻击。
直接上图!!!
做一回伸手党了
-
12222.gif
(118.74 KB, 下载次数: 19)
-
1123123.gif
(62.09 KB, 下载次数: 27)
-
1.png
(57.8 KB, 下载次数: 22)
-
2x.png
(58.44 KB, 下载次数: 24)
-
1.jpg
(945.35 KB, 下载次数: 17)
-
2.jpg
(946.91 KB, 下载次数: 28)
-
3.jpg
(947.78 KB, 下载次数: 21)
-
-
战斗工程.rar
213.95 KB, 下载次数: 115
作者: 灯笼菜刀王 时间: 2019-6-15 15:53
本帖最后由 灯笼菜刀王 于 2019-6-15 15:58 编辑
这个就是真位移了, 一样是每帧改变精灵坐标, 只不过是点和点之间用抛物线移动而不是直线移动
至于怎么做, 你写个公式来让精灵的坐标呈抛物线刷新就可以了, 别问我抛物线公式怎么写, 我只会四则运算
其实复刻又不一定要照搬, 我觉得用RM的素材和模式做出"换汤版"更有味道, 毕竟要FC的那种画面直接去玩原版就好了何必玩你的作品呢~
看看SE, 人家炒个十年前的冷饭都至少也是来个高清版加几个葱花再拿出来捞钱呢
作者: hyrious 时间: 2019-6-15 18:41
我觉得他是事先算好了 y 轴写死的……
以角色待机状态坐标为原点,向上为正数,y 轴变化依次是:-4 55 112 130 100 53(肉眼量的,你可以自己调整x
然后根据抛物线,x 轴平移即可
作者: 芯☆淡茹水 时间: 2019-6-15 22:56
本帖最后由 芯☆淡茹水 于 2019-6-15 23:01 编辑
两点(站位点和怪面前点)
跳跃持续时间(帧数)
确定跳跃幅度并计算每帧xy移动量。
抛物线算法本人不会,当然如果硬憋,憋一天估计会写出一个不是太好的算法。
作者: KB.Driver 时间: 2019-6-16 20:09
本帖最后由 KB.Driver 于 2019-6-16 20:13 编辑
瞎写的玩意,感觉有不少问题,不太追求完美就自己改改参数凑合着用吧
Velocity = Struct.new(:x, :y)
class Sprite
#--------------------------------------------------------------------------
# ● 设置跳跃
# x_inc - X坐标增量
# y_inc - Y坐标增量
# duration - 总体时间
# top_inc - 跳跃高度(可选)
#--------------------------------------------------------------------------
def set_jump(x_inc, y_inc, duration, top_inc = [y_inc, 0].max + 20)
new_x = self.x + x_inc
new_y = self.y - y_inc
top_y = self.y - top_inc
set_jump_xy(new_x, new_y, top_y, duration)
end
def set_jump_xy(new_x, new_y, top_y, duration)
raise "set_jump: top_y should not be smaller than new_y" if top_y > new_y
t = duration / 2
ay = 2 * (top_y - self.y).abs / (t * t).to_f
vx = (new_x - self.x) / t.to_f
vy = (top_y - self.y).abs / t.to_f + 0.5 * ay * t
@v = Velocity.new(vx, vy)
@ay = ay
@t = 0
@new_x, @new_y, @top_y = new_x, new_y, top_y
@real_x, @real_y = self.x, self.y
@duration = duration
@jump_state = :up
end
def update_jump
return if !jumping?
@real_x += @v.x
@real_y -= @v.y
@v.y -= @ay
if @jump_state == :up
@real_y = [@real_y, @top_y].max
if @v.y <= 0 || @real_y == @top_y
#@v.y = 0
@jump_state = :down
end
else # down
@real_y = [@real_y, @new_y].min
end
self.x, self.y = @real_x, @real_y
if @t == @duration || self.y == @new_y
clear_jump
else
@t += 1
end
end
def clear_jump
@v = nil
@ay = nil
@t = nil
@new_x = @new_y = @top_y = nil
@real_x = @real_y = nil
@duration = nil
@jump_state = nil
end
def jumping?
!@jump_state.nil?
end
end
Velocity = Struct.new(:x, :y)
class Sprite
#--------------------------------------------------------------------------
# ● 设置跳跃
# x_inc - X坐标增量
# y_inc - Y坐标增量
# duration - 总体时间
# top_inc - 跳跃高度(可选)
#--------------------------------------------------------------------------
def set_jump(x_inc, y_inc, duration, top_inc = [y_inc, 0].max + 20)
new_x = self.x + x_inc
new_y = self.y - y_inc
top_y = self.y - top_inc
set_jump_xy(new_x, new_y, top_y, duration)
end
def set_jump_xy(new_x, new_y, top_y, duration)
raise "set_jump: top_y should not be smaller than new_y" if top_y > new_y
t = duration / 2
ay = 2 * (top_y - self.y).abs / (t * t).to_f
vx = (new_x - self.x) / t.to_f
vy = (top_y - self.y).abs / t.to_f + 0.5 * ay * t
@v = Velocity.new(vx, vy)
@ay = ay
@t = 0
@new_x, @new_y, @top_y = new_x, new_y, top_y
@real_x, @real_y = self.x, self.y
@duration = duration
@jump_state = :up
end
def update_jump
return if !jumping?
@real_x += @v.x
@real_y -= @v.y
@v.y -= @ay
if @jump_state == :up
@real_y = [@real_y, @top_y].max
if @v.y <= 0 || @real_y == @top_y
#@v.y = 0
@jump_state = :down
end
else # down
@real_y = [@real_y, @new_y].min
end
self.x, self.y = @real_x, @real_y
if @t == @duration || self.y == @new_y
clear_jump
else
@t += 1
end
end
def clear_jump
@v = nil
@ay = nil
@t = nil
@new_x = @new_y = @top_y = nil
@real_x = @real_y = nil
@duration = nil
@jump_state = nil
end
def jumping?
!@jump_state.nil?
end
end
Sprite#update_jump没有写进Sprite#update里面,需要你在对应场景的update中添加
一个使用范例(插入Main以上)
sprite = Sprite.new
sprite.bitmap = Bitmap.new("Graphics/Characters/001-Fighter01")
sprite.src_rect.set(0, 0, sprite.bitmap.width / 4, sprite.bitmap.height / 4)
sprite.x = 640 / 2
sprite.y = 480 / 2
sprite.set_jump(50, 50, 30)
while sprite.jumping? do
sprite.update_jump
Graphics.update
end
sprite.set_jump(-50, -50, 30)
while sprite.jumping? do
sprite.update_jump
Graphics.update
end
sprite = Sprite.new
sprite.bitmap = Bitmap.new("Graphics/Characters/001-Fighter01")
sprite.src_rect.set(0, 0, sprite.bitmap.width / 4, sprite.bitmap.height / 4)
sprite.x = 640 / 2
sprite.y = 480 / 2
sprite.set_jump(50, 50, 30)
while sprite.jumping? do
sprite.update_jump
Graphics.update
end
sprite.set_jump(-50, -50, 30)
while sprite.jumping? do
sprite.update_jump
Graphics.update
end
gif:
作者: guoxiaomi 时间: 2019-6-16 20:27
本帖最后由 guoxiaomi 于 2019-6-16 20:33 编辑
现成的公式在XP的跳跃处理中,XP中有一条事件指令可以让地图上的角色从一个点跳跃到另一个点,在跳跃过程中角色走的路线是抛物线。接下来分析XP是如何实现抛物线的路线的:
我们顺藤摸瓜,首先找到 Game_Character 3 的 jump 方法,在此方法里,执行了以下任务:
1. 调整角色的朝向
2. 将@x和@y设置为目标位置的值
3. 设置跳跃计时@jump_count = @jump_peak * 2
随后找到Game_Character 2 中的 update_jump 方法:
#--------------------------------------------------------------------------
# ● 更新画面 (跳跃)
#--------------------------------------------------------------------------
def update_jump
# 跳跃计数减 1
@jump_count -= 1
# 计算新坐标
@real_x = (@real_x * @jump_count + @x * 128) / (@jump_count + 1)
@real_y = (@real_y * @jump_count + @y * 128) / (@jump_count + 1)
end
#--------------------------------------------------------------------------
# ● 更新画面 (跳跃)
#--------------------------------------------------------------------------
def update_jump
# 跳跃计数减 1
@jump_count -= 1
# 计算新坐标
@real_x = (@real_x * @jump_count + @x * 128) / (@jump_count + 1)
@real_y = (@real_y * @jump_count + @y * 128) / (@jump_count + 1)
end
从这里可以看出,每次更新的时候,@jump_count 会减少 1,最终一直减少到 0。同时,角色的@real_x和@real_y会用此递推公式进行更新。
为了庆祝高考结束,现场解一下递推公式,暂不考虑整除的影响:
数列Sn表示角色的@real_x在第 n 帧的值,则有:@jump_count = N - n,其中 N 是 @jump_count 的初始值。代入递推公式:
S[n+1] = (S[n] * (N - n) + X) / (N - n + 1),这里用 X 代替了 @x * 128,在整个跳跃过程中是不变的。同时我们还知道 S[0] = 初始位置的 @real_x。
整理递推公式得:
S[n+1] / (N - n) - S[n] / (N - n + 1) = X / (N - n) - X / (N - n + 1)
取n=0,1,2...a - 1,代入上面的式子,左右两边分别求和消去相同的项:
S[a] / (N - a + 1) - S[0] / N = X / (N - a + 1) - X / N
得到:
S[a] = S[0] - a * (S[0] - X) / N,是一个等差数列。在a = 0的时候,值为S[0],在a = N的时候,值为X。
上面的推导说明了,在跳跃过程中,角色的真实位置@real_x和@real_y是匀速变换到目标位置的。这个和看上去的抛物线路径并不一样,所以找到最后的地方:Game_Character 1 的 screen_y 方法:
#--------------------------------------------------------------------------
# ● 获取画面 Y 坐标
#--------------------------------------------------------------------------
def screen_y
# 通过实际坐标和地图的显示位置来求得画面坐标
y = (@real_y - $game_map.display_y + 3) / 4 + 32
# 取跳跃计数小的 Y 坐标
if @jump_count >= @jump_peak
n = @jump_count - @jump_peak
else
n = @jump_peak - @jump_count
end
return y - (@jump_peak * @jump_peak - n * n) / 2
end
#--------------------------------------------------------------------------
# ● 获取画面 Y 坐标
#--------------------------------------------------------------------------
def screen_y
# 通过实际坐标和地图的显示位置来求得画面坐标
y = (@real_y - $game_map.display_y + 3) / 4 + 32
# 取跳跃计数小的 Y 坐标
if @jump_count >= @jump_peak
n = @jump_count - @jump_peak
else
n = @jump_peak - @jump_count
end
return y - (@jump_peak * @jump_peak - n * n) / 2
end
在跳跃过程中,y值有一个修正项:y = y0 - 1/2 * (N*N - n*n),在这里用 N 表示 @jump_peak。
注意在跳跃过程中,@jump_count 的值从 @jump_peak * 2 逐步减少到 0,对应 n 的变化范围正好是从 -N 到 N,所以 screen_y 增量从 0 逐渐增大最后回落到 0。
实际显示的角色位置,是一个在 y 方向上与时间呈二次方关系的运动,叠加上角色本身的匀速运动,这是一条抛物线。
最终结论是,直接用XP自带的跳跃功能就行了。
作者: KB.Driver 时间: 2019-6-17 23:27
详见私信
作者: 优乐美 时间: 2022-12-10 10:50
大佬,你能不能把之前那个跳跃战斗范例发下给我,谢谢了。
欢迎光临 Project1 (https://rpg.blue/) |
Powered by Discuz! X3.1 |