Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Developing Asteroids: a series.

13»

Comments

  • dave1707dave1707 Mod
    Posts: 9,733

    @RonJeffries Sorry, I forgot to mention in the write up that the Shield image was 4x the normal size. I had that in the comments in the code.

  • Posts: 1,280

    looks pretty good, thanks!

  • dave1707dave1707 Mod
    edited August 2020 Posts: 9,733

    @RonJeffries I was playing around with the shield hits by the missiles and I came up with this code. Instead of using the actual shield sprites, I just used plain white rectangles. That way nobody has to get the shield sprites to try this code. Just tap the screen multiple times near the bottom or top to shoot the missiles. This still needs some work, but this is just an example.

    Updated version below.
    
  • Posts: 1,280

    interesting and useful idea. surprised to find that out of range sets are ignored.

  • dave1707dave1707 Mod
    Posts: 9,733

    @RonJeffries Heres another version of the shield hits. This shows two options. One is the original random hit within a rectangle. The other is a full hit within a circle. Slide the circ parameter to switch between them. The size of the hit circle can be changed by setting rad in the last function. You can shoot from below or above.

    displayMode(STANDARD)
    
    function setup()
        parameter.boolean("circ",false)
        fill(255,0,0)
        rectMode(CENTER)
        spriteMode(CENTER)
    
        missileWidth=10
        missileHeight=20
        missileTab={}
    
        shieldTab={}
        shieldImg={}
        for s=1,5 do
            shieldImg[s]=image(88,64)
            setContext(shieldImg[s])
            background(255)
            setContext()
            shieldTab[s]=shields(shieldImg[s],vec2(180*s,HEIGHT/2),88,64)
        end
    end
    
    function draw()
        background(0)
        text("tap multiple times near the bottom or top",WIDTH/2,100)    
        for a,b in pairs(missileTab) do
            rect(b.mx,b.my,missileWidth,missileHeight)
            b.my=b.my+b.mv
            if b.my>HEIGHT or b.my<0 then
                table.remove(missileTab,a)
            end
        end
        for s=1,#shieldTab do
            shieldTab[s]:draw()
        end
    end
    
    function touched(t)
        if t.state==BEGAN then 
            v=5
            if t.y>HEIGHT/2 then 
                v=-5
            end
            table.insert(missileTab,{mx=t.x,my=t.y,mv=v})
        end    
    end
    
    shields=class()
    
    function shields:init(shld,pos,sw,sh)
        self.shield=shld
        self.center=pos
        self.width=sw
        self.height=sh 
        self.left=self.center.x-self.width/2
        self.right=self.center.x+self.width/2
        self.bottom=self.center.y-self.height/2
        self.top=self.center.y+self.height/2 
        self.withinRange=false
        self.hit=false
    end
    
    function shields:draw()
        sprite(self.shield,self.center.x,self.center.y)
        for a,b in pairs(missileTab) do
            self:shieldRange(b)
            self:shieldHit(b)
            if circ then
                self:shieldExplodeCirc(a,b)
            else
                self:shieldExplodeRec(a,b)
            end        
        end
    end
    
    function shields:shieldRange(b)
        if b.mx+missileWidth/2>=self.left and 
                b.mx-missileWidth/2<=self.right and 
                b.my+missileHeight/2>self.bottom and 
                b.my-missileHeight/2<self.top then
            self.withinRange=true
        end
    end
    
    function shields:shieldHit(b)
        if self.withinRange then        
            for x=-missileWidth/2,missileWidth/2 do
                for y=-missileHeight/2,missileHeight/2 do
                    xx=(b.mx-(self.left)+x)//1
                    yy=(b.my-(self.bottom)+y)//1
                    if xx>=1 and xx<=self.width and yy>=1 and yy<=self.height then
                        r1,g1,b1=self.shield:get(xx,yy)
                        if r1+g1+b1>0 then
                            self.hit=true
                            self.withinRange=false
                            return
                        end
                    end
                end
            end
        end
    end
    
    function shields:shieldExplodeRec(a,b)
        if self.hit then
            for x=-missileWidth,missileWidth do
                for y=1,15 do
                    for z=1,15 do
                        a1=math.random(-15,15)
                        b1=math.random(25)
                        if b.mv<0 then
                            b1=-b1-missileHeight/2                        
                        end
                        self.shield:set((b.mx-self.left+x+a1)//1,
                            (b.my-self.bottom+y+b1)//1,0,0,0,0)
                    end
                end
            end 
            self.hit=false
            table.remove(missileTab,a)   
        end    
    end
    
    
    function shields:shieldExplodeCirc(a,b)
        if self.hit then
            local rad=15
            local t=rad
            if b.mv<0 then
                t=-rad
            end
            xx=b.mx-self.left
            yy=b.my-self.bottom+t
            for xx1=-rad,rad do
                for yy1=-rad,yy+rad do
                    if xx1^2+yy1^2<rad^2 then
                        self.shield:set((xx1+xx)//1,(yy1+yy)//1,0,0,0,0)
                    end                
                end
            end
            self.hit=false
            table.remove(missileTab,a)   
        end    
    end
    
  • Posts: 1,280

    Thanks, will check it out.

  • Posts: 1,280

    the random one is nicer, isn't it? i was a bit surprised at the way you handled the sequential in-range, actually hit, ok explode logic. interesting, i'll have to think about it to decide how i feel.

  • dave1707dave1707 Mod
    edited August 2020 Posts: 9,733

    @RonJeffries I wanted to make sure the missile was within the bitmap area before I started checking anything. Then when it was within a bitmap range, I checked for any bit overlapped by the missile. As soon as I detected an overlap, I set the explode flag and exited the routine. That way I didn’t spend a lot of time over checking for bit map missile overlaps. I was looking for the first one before calling explode.

    I also liked the random explode, but I wanted to see what a circular explode looked like. Maybe a random explode within a circular area instead of the rectangular area.

  • Posts: 1,280

    yes ... i'd more likely have cascaded the checks or anded them or something. it was an interesting approach that i want to think about. the original game, i think, actually erases just where the missile hits. i'll have to study the code to be sure. for a similar look, i'm thinking the more rectangular explosion is better. not sure yet, tho. thanks!

  • dave1707dave1707 Mod
    Posts: 9,733

    @RonJeffries Just read your latest article where you talked about my code. I found it interesting how you would do things different. By returning true or false from some functions eliminated setting and clearing some variables. Also, the way you check a variable at the start of a function and return immediately instead of putting code within an if statement. I read your articles each time you post something just to see your approach at coding. When I was watching the video when there was a slew of missiles coming down, I noticed some of the missiles were disappearing before they hit anything. That might be caused by the way I’m deleting the missiles. Tables should be traversed in reverse order if things are being shown and deleted in the same for loop. I didn’t think there would be that many missiles at one time.

    PS. I just realized that we live about 150 miles apart. I’m between Toledo and Cleveland.

  • Posts: 1,280

    neighbors, neat! yes, object deletion is tricky. backward should help. i enjoy considering different ways of expressing things and am glad you read my stuff!

  • dave1707dave1707 Mod
    edited August 2020 Posts: 9,733

    @RonJeffries Read your latest article, #16. I kind of look forward to what you have to say and seeing how you build up your code. I thought I’d pull out some code I had about moving invaders. Keep tapping the screen to randomly kill an invader which causes their speed to increase. It’s interesting to see how different our coding styles are. You code more professionally while I just kind of hack stuff to work.

    displayMode(FULLSCREEN)
    
    function setup() 
        rectMode(CENTER) 
        inv=Invaders()    
    end
    
    function draw()
        background(0)
        inv:draw() 
    end
    
    function touched(t)
        inv:touched(t)    
    end
    
    Invaders=class()
    
    function Invaders:init()
        self.cnt=0
        self.delay=0
        self.rev=false
        self.incX=20
        self.decY=0
        self.row=6
        self.invTab={}
        fill(255)
        for y=1,5 do
            self.invTab[y]={}
            for x=1,11 do
                local p=vec2(x*50,HEIGHT-50-y*50)
                self.invTab[y][x]={pos=p,alive=true}
            end
        end
    end
    
    function Invaders:draw()
        self.cnt=0
        for y=1,5 do
            for x=1,11 do
                local i=self.invTab[y][x]
                if i.alive then
                    self.cnt=self.cnt+1
                    sprite(asset.builtin.Space_Art.Part_Red_Hull_3,i.pos.x,i.pos.y,30)
                end
            end
        end
        self:update()
    end
    
    function Invaders:update()
        if self:checkDelay() then
            self.row=self.row-1
            for x=1,11 do
                local i=self.invTab[self.row][x]
                i.pos.x=i.pos.x+self.incX
                i.pos.y=i.pos.y-self.decY
                if (i.pos.x<40 or i.pos.x>WIDTH-40) and i.alive then
                    self.rev=true
                end
            end        
            if self.row==1 then
                self.row=6
                self.delay=0
                self.decY=0      
                if self.rev then
                    self.rev=false
                    self.incX=self.incX*-1 
                    self.decY=20 
                end
            end        
        end
    end
    
    function Invaders:checkDelay()
        self.delay=self.delay+1
        if self.delay>self.cnt/55*9 then
            self.delay=0
            return true
        end 
    end
    
    function Invaders:touched(t)
        if t.state==BEGAN then
            y=math.random(5)
            x=math.random(11)
            self.invTab[y][x].alive=false         
        end
    end
    
  • Posts: 1,280

    nice. i'm not sure "professionally" is quite right, but i do want to explore and show how we can move from something small and hacked together, to something with enough good design to grow for a long time.

    i often like the direct ways you do things. i've almost forgotten how to work that way.

    thanks!

Sign In or Register to comment.