2016-11-15 01:38:05

(Disclaimer: a world built from an array is bad for you and you should use trees or spatial hashes or something to make it faster.)


I'm using an array of objects with simple 3d geometry. Some of them are solid, some are holes, some are "special", meaning event triggers or traps or whathaveyou.
There are too object pointers for handling collisions: "atop" and "bumped". When the player collides with a solid object, atop points to that object if the player is within 20cm of the top, otherwise bumped points to the object.
When a player touches a hole, atop and bumped become null, with the exception that if the player's feet are outside of the hole, atop can point to bumped (otherwise some weird crap can happen).
So, in theory, the array is ordered so that holes come after the objects they're cut/dug/etc into. So the first object is the ground, then a large rock formation, then a hole that makes the rock formation hollow, then a hole to serve as a tunnel connecting the outside and inside of the cave. Everything inside the cave comes after those holes. There is one more hole to cut a chamber in a pyramidal structure at the bottom of the cave, which is followed only by "special" items. I've checked the numbers and the type flags, and if any of them are wrong, it's slipped past me several times.
So, the problem? Well, there are two:
1: you can't touch anything inside the cave, other than the ramp leading inside. the top of that ramp sticks out a bit, whereas the others are fully contained by either the cave or the ground. This appears to apply to event triggers, too, but no promises. I checked, and the loop is not aborting early.
2: At a certain point, the cave just effing vanishes so far as hit detection is concerned. This point is far underground. Most of the time, this results in bumped pointing to the ground--so it basically acts as though there are no other objects, period. This looked like it might be a collision issue, but I checked in several different ways, and the hit detection works as it should. I even put in a check to see if, when bumped is the ground, the player collides with the inside of the cave--and it does.
So, basically, things are just vanishing for no reason. They're in the correct places; hit detection works; it's just ignoring them, somewhy.
I have no idea what's going on.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2016-11-16 22:52:01

do you think you could provide the code? It is not possible for me to formulate an idea of why it's bugging up, because all we have is your explanation, and what you've described sounds right, but sometimes code just doesn't wanna play that way.

If you have issues with Scramble, please contact support at the link below. I check here at least once a day, so this is the best avenue for submitting your issues and bug reports.
https://stevend.net/scramble/support

2016-11-17 15:06:43

Eh, why not?

    form@ bounds=get_bounds(n, me);
    //if(i==0 and v.length()>0) voice.speak("success! Moving in frame " + fps.frame + ", at " + v.length() + "meters per second.");
    
    // physics:
    object@ atop=null, bumped=null;
    form@ targ=bounds.translate(v*dt); // -_-
    bool swimming=false;
    bool inside=(i==0 and map[2].bounds.contains(me));
    int highest=-1;
    for(uint j=0; j<map.length(); j++) {
        object@ o=map[j];
        if(o.type==s_intangible) continue;
        highest=j;
        if(!collide(targ, o.bounds)) continue;
        if(o.type==s_hole) {
            @atop=null;
            if(@bumped!=null and !o.bounds.contains(me) and bumped.bounds.contains(me)) {@atop=bumped; @targ=targ.translate(0,0,0.15);}
            @bumped=null;
        }// holes.
        else if(o.type==s_liquid) {
            // I don't know what to do with this, honestly.
            swimming=true;
        }// yay, swimming.
        else if(o.type==s_solid) {
            // can we stand on it?
            // My standard for this is pitiful.
            form@ targ2=targ.translate(0, 0, 0.2);
            if(!collide(o.bounds, targ2)) {
                @atop=o;
                //@targ2=targ.translate(0,0,0.1);
                //if(collide(targ2, atop.bounds)) @targ2=targ2.translate(0,0,0.05);
                //@targ=targ2; // I'm not sure this is a good idea.
            }
            else @bumped=o;
        }// solids.
        else if(o.type==s_special) {
            if(string_left(o.name, 5)=="event") {
                if(i!=0) continue;
                // Events are kinda tricky?
                int id=string_to_number(string_trim_left(o.name, 5));
                bool removeme=true;
                if(o.data.exists("script")) script(true, o.gets("script"));
                else voice.speak("Event " + id);
                if(id<0) {removeme=false; @bumped=o; @targ=bounds;}
                if(removeme) {
                    map.remove_at(j);
                    j--;
                    pool.play_stationary(jla + "jla/menu/submenu.wav", false); // Temp for debugging.
                }// removing events from the map.
                //continue;
            }// events.

        }// traps, events, etc.
        if(inside and j>5) {alert("Huh.", "It... worked?"); exit();}
    }// collision loop.
    if(i==0) clipboard_copy_text(highest + "Stepping " + n + " with v" + toString(v) + ". Atop " + ((@atop==null) ? "nothing" : atop.name) + ", bumping " + ((@bumped==null) ? "nothing" : bumped.name) + ", new position should be " + toString(me+(v*dt)) + ". Counter " + counter + ", state " + state + ", airwind.playing: " + airwind.playing);
    if(@atop==null) {
        if(swimming) v.z=(v.z<-10) ? -10.0 : (v.z-(4.5*dt));
        else v.z-=9.8*dt;
    }// gravity.
    else {
        if(v.z<0.0 and !collide(bounds, atop.bounds)) {
            vector te=me+(v*dt);
            te.z+=0.1;
            while(atop.bounds.contains(te)) te.z+=0.02;
            while(!atop.bounds.contains(te)) te.z-=0.01;
            me.z=te.z-(v.z*dt);
            if(v.z<=-20.0 or counter<0.0 or state=="fall") {
                if(slot>=0) pool.destroy_sound(slot);
                string toplay=atop.gets("terrain");
                if(toplay=="" or ((!file_exists(steps + toplay + "/fall1.wav")) and !file_exists(steps + toplay + "/fall1.ogg"))) toplay="stone";
                string ext=(!file_exists(steps + toplay + "/fall1.wav")) ? ".ogg" : ".wav";
                int val=random(1, 4);
                int tries=0;
                while(tries<40 and !file_exists(steps + toplay + "/fall" + val + ext)) {tries++; val=random(1, val);}
                slot=pool.play_3d(steps + toplay + "/fall" + val + ext, camera.x, camera.y, camera.z, me.x, me.y, me.z, getd("face"), false, true);
                if(hp>0 and math_random()>0.5 and i==0) voiceplay(i, sfx2 + "whit" + random(0, 7) + ".wav");
            }// fall.
            else {
                string toplay=atop.gets("terrain");
                if(toplay=="") toplay="stone";
                pool.play_3d(steps + toplay + "/run" + random(1, 3) + ".wav", camera.x, camera.y, camera.z, me.x, me.y, me.z, getd("face"), false);
                pool.play_3d(steps + toplay + "/run" + random(4, 6) + ".wav", camera.x, camera.y, camera.z, me.x, me.y, me.z, getd("face"), false);
            }// landing on feet.
        }// landing.
        v.z=0.0;
    }// atop.
    if(@bumped==null) {
        @bounds=targ;
        me+=v*dt;
        if(@atop!=null and (v.x!=0 or v.y!=0 or v.z!=0)) {
            double sc=getd(i + ".stepcounter");
            sc-=dt;
            if(sc<=0.0) {
                sc=1.0/v.length();
                if(sc>1.0) sc=1.0; else if(sc<0.2) sc=0.25;
                // step sounds are tricky.
                string terrain=atop.gets("terrain");
                if(terrain=="") terrain="dirt";
                // Steps for robots, monsters, imps... most everything.
                pool.play_3d(steps + terrain + "/run" + random(1, 5) + ".wav", camera.x, camera.y, camera.z, me.x, me.y, me.z, getd("face"), false);
            }
            a.set(i + ".stepcounter", sc);
        }// steps.
        
    }// move.
    else if(v.length()>0.0) {
        string toplay=bumped.gets("bump");
        if(toplay=="") toplay=steps + bumped.gets("terrain") + "/bump.ogg";
        if(!file_exists(toplay)) toplay=steps + "stone/bump.ogg";
        clipboard_copy_text(n + " bumping " + bumped.name + ", at " + toString(me) + ", velocity " + toString(v) + ", facing " + face);
        pool.play_3d(toplay, camera.x, camera.y, camera.z, me.x+(v.x*dt), me.y+(v.y*dt), me.z+(v.z*dt), getd("face"), false);
        v=new_vector(0,0, 0); // Interesting note: wall-jumping.
        if(i==0 and @bumped==@map[0] and geti("stage")==0) {
            if(collide(map[2].bounds, targ)) {alert("GAAAAAAH!", "THIS IS SO MUCH BULLCRAP!"); exit();}
            else {alert("*sigh*", "At least it\'s consistent."); exit();}
        }// So sick of this crap.
    }// bump.
    
看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2016-11-22 03:15:41

It looks like this thread died, so a couple things for you since I'm seriously confused as to what you're trying to pull off.
1) Write tests. Elevate your code into modules and write tests. Your tests should be separated by module. Have it call individual functions and check for positive and negatives. This is a really good  solution to finding problems.
2) Unless 100% required do not nest more than two or thre if statements inside each other. You should theoretically be able to construct truth tables from your if statements to figure out exactly what you're doing. a ton of your code has random comments and it's not documented. Move your separate checks into individual functions (makes testing easier) and from there call those functions from your main check.
3) You sound intelligent... why are you using BGT again? Especially if you have a grasp of game trees and the like.

2016-11-22 15:40:51

1) I'm not sure I understand what specifically you're suggesting I do? Also I'm using dictionaries for most things and want to avoid referencing them too much in a single frame.

2) I think I need examples, here, preferably with an explanation of the advantages. I do hate going more than 4 levels deep (if I'm tabbing more than 4 or 5 times at the beginning of a line, I try to figure out if there's a way around this which isn't too inconvenient). At the same time, breaking code up into too many separate parts tends to make it more, not less confusing.

3) Because I feel like it. Intelligence!=impressing all the other intelligent people; intelligence==the ability to adapt to a wide variety of situations and satisfy one's preferences. Granted, I am bad at both of those, so maybe my STEM skills (or at least what they looked like 10 years ago) are a weird fluke.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2016-11-22 21:36:59

1) Lets say you have a module that does something. For right now lets just say it's a simple math module and it contains one function:
function sum(a,b)
return a+b
endfunction
You'd have a math_tests module as well, and you would have functions that would test the sum function to see if you're getting what you want out of it. You'll need to create some utility functions especially for BGT, but it'd look something like this (again pseudo code):
function sum_tests()
test_that(sum(1,1), 2)
test_that(sum(0,0), 0)
test_that(sum(-1,1), 0)
endfunction

Your code should not be harder to read if you break it up. Methods should have one purpose and do that well. If you're putting multiple points in your functions they should and can be broken down. If that makes them harder to understand or read, consider adopting a naming convention which allows your code to be easier to read.
While I understand that this is easier said than done, you could have checks like IsTunnel, isSolid, etc which can do some of your checking for you and which you would call from your movement logic.

As to point 3, that was more of a joke. I did want to point out that BGT has many shortcomings, many of which are performance and lack of any sane development paradigms and tools. Most languages have many many tools written for you which you can make great use of, this includes a good system for unit tests. Unit tests are in the most basic form what I shoed you, but you'll end up wanting mach objects, etc and that's something you'd have to do. Basically you're going to have to reinvent the wheel.

2016-11-23 06:26:37

Hm, the more javafied code structure I used in the JFIMA and the rest of the console games do things more like what you mean--"isTunnel" and "isSlope" and "getHeightAt" are all methods.
On the other hand, I kinda think the test module you described feels weird, in that it seems more intuitive to just include the contents of all those test functions in a single test function--am I calling these anywhere else? The purpose of functions and methods is reusability, right? If I don't expect to reuse something, is there a point in moving it? (Yes. I think I once tried to put keychecks and parts of stepping all in the main function in a pygame program. I have no idea why. I think something about python functions makes me more apprehensive, somewhy.)

But basically, the way I'd done it in Java wasn't getting me to finish much, so I just threw the idea of doing everything in classes out, in the hopes that a less rigid dict or array-based code structure would result in more finished products. Once I start it that way, modulifying the movement is more trouble than it needs to be.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2019-09-22 16:24:27

FYI, the problem was in cylinder collisions. Somewhere or other, I was using copies placed at the origin, which was causing all sorts of weirdness. This didn't show up in the 3d editor because that was using a point for the cursor. A very silly mistake that somehow took over two years to catch.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.