topdown vehicle on the wall

Official forum for the Chipmunk2D Physics Library.
Post Reply
velkyel
Posts: 2
Joined: Wed May 15, 2013 4:53 pm
Contact:

topdown vehicle on the wall

Post by velkyel »

hello,

i have this following issue:

one simple car rigid body (only box, no constraints) and some static boxes (grey area on pictures). Most of the time i i'm using custom integration functions because car object has quite different and complex physics.

So, on first picture there is car goint to the wall (grey). At this point it's driven by my own integration (there traction, rotation by keyb. arrows etc..). When collision occurred I simply handover math (calculations of velocities and position) to default chipmunk integration functions and waiting for separation or velocity drop near to zero. Most of collision situation it works nice, but..

Image

On next picture, car is moving forward along the wall (still touching wall) and all calculations are on chipmunk (moves slower because contact friction).

Image

That's ok. In this situation I'd like to give player option to press left key to turn left and make separation earlier and return to my car integration based on last default integration values. But I don't know how to do this. Apply "side" impulse (or force?) at between front wheels when left/right key pressed?

Thanks for advice
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: topdown vehicle on the wall

Post by slembcke »

I guess it seems to me that the problem is that you have implemented it to be all or nothing. Either Chipmunk is responsible for the body or you are and there is no mixing. Since it's a top down game, cpBodyUpdateVelocity() is going to be doing little to nothing. You might as well always call that at the beginning of your velocity update and then add your velocity changes on top of that.

Do you actually have the position integration function overridden? What for?
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
velkyel
Posts: 2
Joined: Wed May 15, 2013 4:53 pm
Contact:

Re: topdown vehicle on the wall

Post by velkyel »

thanks for answer. You are right, own position integration is not needed. Now i'm overriding only velocity integration. But collision (especially response) doesn't look too much realistic - most of collisions simply stop vehicle body on static obstacle without bounce or any nice response, any hint please?

My prototype code now looks like that (very simplified):

Code: Select all

import time
from inge import *
from utils import *
import pymunk as pm

def sign(v):
    if v < 0: return -1
    if v > 0: return 1
    return 0

def collisionStarted(space, arbiter, car):
    #car.object_hit = True #True
    #print("Collision started", car.body.velocity * dt, car.vel)
    return True

def collisionSeparated(space, arbiter, car):
    #car.object_hit = False
    print("Objects separated")
    return True

def update_pymunk_velocity(body, gravity, damping, dt):
    # if car.object_hit:
    #     print('gravity: %s, damping: %s, body.velocity: %s, ang: %s'
    #           % (gravity, damping, body.velocity * dt, body.angular_velocity * dt))
    #     pm.Body.update_velocity(body, gravity, damping, dt)
    #     print(' ----> %s, ang: %s' % (body.velocity * dt, body.angular_velocity * dt))
    #     car.object_hit = False
    # else:
    #     print('car -> body')
    body.velocity = (car.vel.x / dt, car.vel.y / dt)
    body.angular_velocity = car.angular_vel / dt
        
class Camera:
    def __init__(self):
        self.prev_rot = 0
        self.rot = 0
        self.rotate = False
        self.rot_speed = 1

    def update(self, car):
        self.prev_rot = self.rot
        forwangle = -car.rot + math.pi * 0.5
        self.rot = lerp(self.rot, forwangle, dt * self.rot_speed)

    def modelview(self, car, visual_interpolation):
        if self.rotate:
            angle = lerp(self.prev_rot, self.rot, visual_interpolation)
        else:
            angle = 0
        return Quat.rotation_z(angle).to_mat4() * Mat4.translation(-car.visual_pos(visual_interpolation))

class Obstacle:
    def __init__(self, dim):
        self.dim = dim
        self.color = Vec4(1, 1, 1, 0.5)
        # for pymunk
        self.body = pm.Body() # no params -> static body
        self.body.position = (self.dim.min.x + (self.dim.w() / 2), self.dim.min.y + self.dim.h() / 2)
        self.shape = pm.Poly.create_box(self.body, (self.dim.w(), self.dim.h()))
        self.shape.friction = 0.2
        self.elasticity = 1.0

    def draw(self):
        draw.rectangle(self.dim, self.color)

class Car:
    def __init__(self, tex_filename, dim):
        # konfigurovatelne hodnoty:
        self.accel = 0.006
        self.steer_speed = 0.04
        self.drift = 0.98
        self.traction_min = 1
        self.traction_max = 50
        self.traction_rate = 1.05
        self.speed_max = 0.6
        self.speed_min = -0.3
        self.speed_slide = 0.2
        self.steering_curve = EnvCurve(0.15, 0.75, 0.4, 0.5, 0.5, 1)
        self.mass = 1.0
        self.moment = pm.moment_for_box(self.mass, dim.x, dim.y)
        self.body = pm.Body(self.mass, self.moment)
        self.shape = pm.Poly.create_box(self.body, (dim.x,dim.y))
        self.shape.friction = 0.8 #61
        self.shape.elasticity = 1.0
        self.shape.collision_type = 1
        #self.separation_time = time.time()
        self.body.velocity_func = update_pymunk_velocity
        #self.object_hit = False
        self.mesh = Mesh.textured_rectangle(Rect.xywh(-dim.x * 0.5, -dim.y * 0.5, dim.x, dim.y))
        self.efx = Effect.default2d(texture0 = load_texture(tex_filename).id)
        self.reset(Vec2(), 0)

    def reset(self, pos, rot):
        self.pos = pos.copy()
        self.rot = rot
        self.traction = self.traction_min
        self.speed = 0
        self.vel = Vec2()
        self.reset_movement()
        self.angular_vel = 0
        
        self.body.position = (self.pos.x, self.pos.y)
        self.body.angle = self.rot
        
    def update(self):
        self.pos = Vec2(self.body.position[0], self.body.position[1])
        self.vel = Vec2(self.body.velocity[0], self.body.velocity[1]) * dt
        self.rot = self.body.angle
        self.speed = self.vel.length() * sign(self.speed)

        if key_down(KEY_LEFT) or key_down(KEY_RIGHT):
            if self.speed > self.speed_slide:
                self.traction = min(self.traction_max, self.traction * self.traction_rate)
            else:
                self.traction = max(self.traction_min, self.traction / self.traction_rate)
            self.angular_vel = self.steer_speed * self.steering_curve.evaluate(abs(self.speed) / self.speed_max) * sign(self.speed)
            if key_down(KEY_RIGHT): self.angular_vel = -self.angular_vel
            #self.rot += self.angular_vel
        else:
            self.angular_vel = 0
            self.traction = max(self.traction_min, self.traction / self.traction_rate)

        if key_down(KEY_UP):
            self.speed = min(self.speed + self.accel, self.speed_max)
        elif key_down(KEY_DOWN):
            self.speed = max(self.speed - self.accel, self.speed_min)
        else:
            self.speed *= self.drift
            self.traction = max(self.traction_min, self.traction / self.traction_rate)

        self.vel.x += ((math.cos(self.rot) * self.speed) - self.vel.x) / self.traction
        self.vel.y += ((math.sin(self.rot) * self.speed) - self.vel.y) / self.traction
        #self.pos += self.vel

    def reset_movement(self):
        self.prev_pos = self.pos.copy()
        self.prev_rot = self.rot

    def visual_pos(self, visual_interpolation):
        v = self.prev_pos.lerp(self.pos, visual_interpolation)
        return Vec3(v.x, v.y, 0)

    def visual_rot(self, visual_interpolation):
        return lerp(self.prev_rot, self.rot, visual_interpolation)

    def draw(self, visual_interpolation):
        self.efx.world = Mat4.translation(self.visual_pos(visual_interpolation)) * Quat.rotation_z(self.visual_rot(visual_interpolation)).to_mat4()
        gfx_render(self.efx, self.mesh)

def draw_all(visual_interpolation):
    gfx_clear(COLOR_BUFFER | DEPTH_BUFFER)
    w = 50
    h = w * window_h() / window_w()
    gfx_projection(Mat4.ortho(-w, w, -h, h, -1, 1))
    gfx_modelview(camera.modelview(car, visual_interpolation))
    render_road(wired = False)
    car.draw(visual_interpolation)
    for obstacle in obstacles: obstacle.draw()
    
    gfx_projection(Mat4.ortho(0, viewport_w(), viewport_h(), 0, -1, 1))
    gfx_modelview(Mat4())
    draw.text(0, viewport_h() - font_h() * 3, 'speed: %.3f' % car.speed)
    draw.text(0, viewport_h() - font_h() * 2, 'traction: %.3f' % car.traction)
    draw.text(0, viewport_h() - font_h(), 'real speed: %.3f' % car.vel.length())
    gfx_swap()
    fps.trigger()

def update():
    car.reset_movement()
    car.update()
    camera.update(car)
    if key_down(KEY_ESC) or not window_opened(): quit()
    poll_window_events()

space = pm.Space()
space.gravity = (0.0, 0.0)
#space.damping = 1.0   # 0.8 = 20% ztraty rychlosti / s
open_window(800, 600, False, False, 0)

obstacles = [Obstacle(Rect.xyxy(-140, 60, -150, 90)),
             Obstacle(Rect.xyxy(-90, 60, -100, 70)),
             Obstacle(Rect.xyxy(-130, 80, -100, 130)),
             Obstacle(Rect.xyxy(-300, -10, 300, 10))]
for obstacle in obstacles:
    space.add(obstacle.shape)
car = Car('car1_body_red.png|nomips', Vec2(4.3, 1.8))
space.add(car.body, car.shape)
space.add_collision_handler(1, 0, begin=collisionStarted, pre_solve=None,
                        post_solve=None, separate=collisionSeparated, car=car)


camera = Camera()

load_track('track1.json', car)

dt = 1 / 60
accumulator = 0

while 1:
    update_frame_time()
    accumulator += frame_dt()
    while accumulator >= dt:
        accumulator -= dt
        update()
        print('step')
        space.step(dt)
        print('-' * 30)
    draw_all(accumulator / dt)

Post Reply

Who is online

Users browsing this forum: No registered users and 30 guests