Hi there,
I'm making a scorched earth-style game and it's all coming together pretty well, but I'm having some real problems with collision. Right now what I've got is pretty rudimentary but I can't work out how to do it any better. Basically when the tank fires a shot, the shot moves in a parabola with variables yspeed and xspeed that get added on to the y and x positions of the shot each frame. The shot cannot collide with anything for two frames (to prevent collision with the tank itself) but after that, the shot should explode on contact with any pixel that isn't the colour of the background (i.e. black). However, if moving at a decent speed it will usually move through walls for a frame or so before exploding.

I've attached the cartridge and the relevant collision code.

 function shot:update() if self.timeout > 0 then self.x = flr(self.x + self.xspeed) self.y = flr(self.y + self.yspeed) self.yspeed = self.yspeed + gravity self.timeout -= 1 else if self.x>=127 then self.x = 127 fired = false end if self.x<=0 then self.x = 0 fired = false end if self.y>=127 then self.y = 127 fired = false explode = true sfx(1,1) end if pget(self.x,self.y+3)!=0 and pget(self.x,self.y+3)!=textclr then fired = false explode = true sfx(1,1) end self.x = flr(self.x + self.xspeed) self.y = flr(self.y + self.yspeed) self.yspeed = self.yspeed + gravity end end
P#27653 2016-08-29 12:50 ( Edited 2016-09-01 13:14)

Test each point from the last position to the current. As soon as it hits anything stop and explode. Depending on your movement implementation you could either use sth like bresenham or simply divide the shot's dx and dy by some factor depending on its current speed.
Good luck!

P#27657 2016-08-29 13:38 ( Edited 2016-08-29 17:38)

I would go with the latter @johanp suggestion. Since the bullet is the only thing moving really, you might as well just waste a lot of cycles updating it's position at 10x or 100x the actual framerate. All you need to do is add a loop and divide the speed by that amount each step.

Not efficient maybe, but neither is wasting all those cycles doing nothing. ;)

P#27660 2016-08-29 14:32 ( Edited 2016-08-29 18:32)

I have to ask the obvious question. Isn't there a collision detection routine in PICO ?

Function CollideImage:Object

P#27682 2016-08-29 20:12 ( Edited 2016-08-30 00:12)

Nope, it's just that bare. The only things you get are the bank of sounds/"songs", and the bank of "sprites"/map. Just like the songs just point to a series of sounds, the map just references the sprites. (and the sprites can have flags set, but they aren't objects or anything at all. you have to manually deal with tracking, collision, iterating through for whatever updates, etc)

P#27695 2016-08-29 22:28 ( Edited 2016-08-30 02:28)
1

Well, if we're going old-school, sounds like we are. The easiest way to detect collision between two points I've used in the past for my games is:

if abs(x1-x2)<8 and abs(y1-y2)<8 then POW

where x1&y1 is the location of sprite#1 and x2&y2 are the location for sprite#2, both sized at 8x8 pixels.

P#27696 2016-08-29 23:19 ( Edited 2016-08-30 03:20)

what johanp & slembcke said.
use the max number of pixels travelled on x or y as steps

something like that:

 dx=nx-ox -- new_pos-old_pos dy=ny-oy steps=max(abs(dx),abs(dy)) sdx=dx/steps sdy=dy/steps for s=1,steps do x=ox+sdx*s y=oy+sdy*s c=pget(x,y) if (c!=air) boom(x,y) break end

this will test some (air) pixels multiple times, but that's a really negligible overhead.

P#27706 2016-08-30 05:49 ( Edited 2016-08-30 09:50)

@ultrabrite: this works for shots fired left, but shots fired right explode in mid-air. Any idea why this may be?

EDIT: Realised this isn't particularly helpful. Here's the implemented code:

 function shot:collision() local dx = self.x-self.lastx local dy = self.y-self.lasty local steps = max(abs(dx),abs(dy)) local sdx = dx/steps local sdy = dy/steps for s=1,steps do testx = self.lastx+sdx*s testy = self.lasty+sdy*s c = pget(testx,testy) if c!=0 and c!= textclr then self.x=testx self.y=testy fired = false explode = true sfx(1,1) break end end end
P#27720 2016-08-30 14:45 ( Edited 2016-09-01 09:21)

Bump

P#27826 2016-09-01 06:04 ( Edited 2016-09-01 10:04)

sorry I didn't notice!

the missile might be testing itself, try adding its color alongside air & text. hard to say why it wouldn't happen on the left though.

P#27827 2016-09-01 07:54 ( Edited 2016-09-01 11:56)

I've fixed it by changing the colour check to just check the floor colour - it means the shots won't collide directly with tanks now, but it fixes the issue, so it's better than before :) Thanks for the help!

P#27831 2016-09-01 08:44 ( Edited 2016-09-01 12:44)

but you'll get the same problem, missile moving thru tanks at high speed.
though you could test distances from missile to tanks at every testx/testy.

P#27834 2016-09-01 09:14 ( Edited 2016-09-01 13:14)

late to the party and might be unrelated,
but this works great for circle-circle continuous collision,

returns:
the exact timestep (0-1)